diff options
Diffstat (limited to 'tools/assistant')
298 files changed, 38928 insertions, 0 deletions
diff --git a/tools/assistant/assistant.pro b/tools/assistant/assistant.pro new file mode 100644 index 0000000..08d0d4b --- /dev/null +++ b/tools/assistant/assistant.pro @@ -0,0 +1,8 @@ +TEMPLATE = subdirs +CONFIG += ordered + +SUBDIRS += lib/fulltextsearch \ + lib \ + tools \ + compat \ + compat/lib \
\ No newline at end of file diff --git a/tools/assistant/compat/Info_mac.plist b/tools/assistant/compat/Info_mac.plist new file mode 100644 index 0000000..b1e6336 --- /dev/null +++ b/tools/assistant/compat/Info_mac.plist @@ -0,0 +1,18 @@ +<?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/LICENSE.GPL b/tools/assistant/compat/LICENSE.GPL new file mode 100644 index 0000000..b6e1c33 --- /dev/null +++ b/tools/assistant/compat/LICENSE.GPL @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/tools/assistant/compat/assistant.icns b/tools/assistant/compat/assistant.icns Binary files differnew file mode 100644 index 0000000..6291dd3 --- /dev/null +++ b/tools/assistant/compat/assistant.icns diff --git a/tools/assistant/compat/assistant.ico b/tools/assistant/compat/assistant.ico Binary files differnew file mode 100644 index 0000000..9e1b83f --- /dev/null +++ b/tools/assistant/compat/assistant.ico diff --git a/tools/assistant/compat/assistant.pro b/tools/assistant/compat/assistant.pro new file mode 100644 index 0000000..e865d6b --- /dev/null +++ b/tools/assistant/compat/assistant.pro @@ -0,0 +1,84 @@ +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 new file mode 100644 index 0000000..dae1f48 --- /dev/null +++ b/tools/assistant/compat/assistant.qrc @@ -0,0 +1,37 @@ +<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 new file mode 100644 index 0000000..b4786ce --- /dev/null +++ b/tools/assistant/compat/assistant.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "assistant.ico" diff --git a/tools/assistant/compat/compat.pro b/tools/assistant/compat/compat.pro new file mode 100644 index 0000000..1086f4c --- /dev/null +++ b/tools/assistant/compat/compat.pro @@ -0,0 +1,84 @@ +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 new file mode 100644 index 0000000..b2eba11 --- /dev/null +++ b/tools/assistant/compat/config.cpp @@ -0,0 +1,438 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 new file mode 100644 index 0000000..0858ad8 --- /dev/null +++ b/tools/assistant/compat/config.h @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 new file mode 100644 index 0000000..31e1040 --- /dev/null +++ b/tools/assistant/compat/docuparser.cpp @@ -0,0 +1,433 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 new file mode 100644 index 0000000..181a8f1 --- /dev/null +++ b/tools/assistant/compat/docuparser.h @@ -0,0 +1,166 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 new file mode 100644 index 0000000..cd0cc06 --- /dev/null +++ b/tools/assistant/compat/fontsettingsdialog.cpp @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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/fontsettingsdialog.h b/tools/assistant/compat/fontsettingsdialog.h new file mode 100644 index 0000000..e4607aa --- /dev/null +++ b/tools/assistant/compat/fontsettingsdialog.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef _FONT_SETTINGS_DIALOG_H_ +#define _FONT_SETTINGS_DIALOG_H_ + +#include <QtCore/QObject> +#include <QtGui/QDialog> + +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_ + + +QT_END_NAMESPACE diff --git a/tools/assistant/compat/helpdialog.cpp b/tools/assistant/compat/helpdialog.cpp new file mode 100644 index 0000000..4ea97d0 --- /dev/null +++ b/tools/assistant/compat/helpdialog.cpp @@ -0,0 +1,1331 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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(const QString&)), this, SLOT(updateSearchButton(const QString&))); + + connect(ui.resultBox, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showListItemMenu(QPoint))); + + cacheFilesPath = QDir::homePath() + QLatin1String("/.assistant"); //### Find a better location for the dbs + + ui.editIndex->installEventFilter(this); + + ui.framePrepare->hide(); + connect(qApp, SIGNAL(lastWindowClosed()), SLOT(lastWinClosed())); + + ui.termsEdit->setValidator(new SearchValidator(ui.termsEdit)); + + actionOpenCurrentTab = new QAction(this); + actionOpenCurrentTab->setText(tr("Open Link in Current Tab")); + + actionOpenLinkInNewWindow = new QAction(this); + actionOpenLinkInNewWindow->setText(tr("Open Link in New Window")); + + actionOpenLinkInNewTab = new QAction(this); + actionOpenLinkInNewTab->setText(tr("Open Link in New Tab")); + + itemPopup = new QMenu(this); + itemPopup->addAction(actionOpenCurrentTab); + itemPopup->addAction(actionOpenLinkInNewWindow); + itemPopup->addAction(actionOpenLinkInNewTab); + + ui.tabWidget->setElideMode(Qt::ElideNone); + + contentList.clear(); + + initDoneMsgShown = false; + fullTextIndex = 0; + indexDone = false; + titleMapDone = false; + contentsInserted = false; + bookmarksInserted = false; + setupTitleMap(); + +} + +void HelpDialog::processEvents() +{ + qApp->processEvents(QEventLoop::ExcludeUserInputEvents); +} + + +void HelpDialog::lastWinClosed() +{ + lwClosed = true; +} + +void HelpDialog::removeOldCacheFiles(bool onlyFulltextSearchIndex) +{ + if (!verifyDirectory(cacheFilesPath)) { + qWarning("Failed to created assistant directory"); + return; + } + QString pname = QLatin1String(".") + Config::configuration()->profileName(); + + QStringList fileList; + fileList << QLatin1String("indexdb40.dict") + << QLatin1String("indexdb40.doc"); + + if (!onlyFulltextSearchIndex) + fileList << QLatin1String("indexdb40") << QLatin1String("contentdb40"); + + QStringList::iterator it = fileList.begin(); + for (; it != fileList.end(); ++it) { + if (QFile::exists(cacheFilesPath + QDir::separator() + *it + pname)) { + QFile f(cacheFilesPath + QDir::separator() + *it + pname); + f.remove(); + } + } +} + +void HelpDialog::timerEvent(QTimerEvent *e) +{ + Q_UNUSED(e); + static int opacity = 255; + help->setWindowOpacity((opacity-=4)/255.0); + if (opacity<=0) + qApp->quit(); +} + + +void HelpDialog::loadIndexFile() +{ + if (indexDone) + return; + + setCursor(Qt::WaitCursor); + indexDone = true; + ui.labelPrepare->setText(tr("Prepare...")); + ui.framePrepare->show(); + processEvents(); + + QProgressBar *bar = ui.progressPrepare; + bar->setMaximum(100); + bar->setValue(0); + + keywordDocuments.clear(); + QList<IndexKeyword> lst; + QFile indexFile(cacheFilesPath + QDir::separator() + QLatin1String("indexdb40.") + + Config::configuration()->profileName()); + if (!indexFile.open(QFile::ReadOnly)) { + buildKeywordDB(); + processEvents(); + if (lwClosed) + return; + if (!indexFile.open(QFile::ReadOnly)) { + QMessageBox::warning(help, tr("Qt Assistant"), tr("Failed to load keyword index file\n" + "Assistant will not work!")); +#if defined Q_WS_WIN || defined Q_WS_MACX + startTimer(50); +#endif + return; + } + } + + QDataStream ds(&indexFile); + quint32 fileAges; + ds >> fileAges; + if (fileAges != getFileAges()) { + indexFile.close(); + buildKeywordDB(); + if (!indexFile.open(QFile::ReadOnly)) { + QMessageBox::warning(help, tr("Qt Assistant"), + tr("Cannot open the index file %1").arg(QFileInfo(indexFile).absoluteFilePath())); + return; + } + ds.setDevice(&indexFile); + ds >> fileAges; + } + ds >> lst; + indexFile.close(); + + bar->setValue(bar->maximum()); + processEvents(); + + for (int i=0; i<lst.count(); ++i) { + const IndexKeyword &idx = lst.at(i); + indexModel->addLink(idx.keyword, idx.link); + + keywordDocuments << HelpDialog::removeAnchorFromLink(idx.link); + } + + indexModel->publish(); + + ui.framePrepare->hide(); + showInitDoneMessage(); + setCursor(Qt::ArrowCursor); +} + +quint32 HelpDialog::getFileAges() +{ + QStringList addDocuFiles = Config::configuration()->docFiles(); + QStringList::const_iterator i = addDocuFiles.constBegin(); + + quint32 fileAges = 0; + for (; i != addDocuFiles.constEnd(); ++i) { + QFileInfo fi(*i); + if (fi.exists()) + fileAges += fi.lastModified().toTime_t(); + } + + return fileAges; +} + +void HelpDialog::buildKeywordDB() +{ + QStringList addDocuFiles = Config::configuration()->docFiles(); + QStringList::iterator i = addDocuFiles.begin(); + + // Set up an indeterminate progress bar. + ui.labelPrepare->setText(tr("Prepare...")); + ui.progressPrepare->setMaximum(0); + ui.progressPrepare->setMinimum(0); + ui.progressPrepare->setValue(0); + processEvents(); + + QList<IndexKeyword> lst; + quint32 fileAges = 0; + for (i = addDocuFiles.begin(); i != addDocuFiles.end(); ++i) { + 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 new file mode 100644 index 0000000..29d77d9 --- /dev/null +++ b/tools/assistant/compat/helpdialog.h @@ -0,0 +1,184 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 new file mode 100644 index 0000000..acd1372 --- /dev/null +++ b/tools/assistant/compat/helpdialog.ui @@ -0,0 +1,404 @@ +<ui version="4.0" > + <author></author> + <comment>********************************************************************* +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 new file mode 100644 index 0000000..d3ddc29 --- /dev/null +++ b/tools/assistant/compat/helpwindow.cpp @@ -0,0 +1,247 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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/helpwindow.h b/tools/assistant/compat/helpwindow.h new file mode 100644 index 0000000..f1327b5 --- /dev/null +++ b/tools/assistant/compat/helpwindow.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef HELPWINDOW_H +#define HELPWINDOW_H + +#include <QTextBrowser> + +QT_BEGIN_NAMESPACE + +class MainWindow; +class QKeyEvent; +class QMime; +class QMouseEvent; +class QMenu; + +class HelpWindow : public QTextBrowser +{ + 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 ); + + void mousePressEvent(QMouseEvent *e); + void keyPressEvent(QKeyEvent *); + +signals: + void chooseWebBrowser(); + void choosePDFReader(); + +protected: + virtual void contextMenuEvent(QContextMenuEvent *e); + virtual void mouseReleaseEvent(QMouseEvent *e); + +protected slots: + void ensureCursorVisible(); + +private slots: + void openLinkInNewWindow(); + void openLinkInNewPage(); + + bool isKDERunning() const; + +private: + bool hasAnchorAt(const QPoint& pos); + + MainWindow *mw; + QString lastAnchor; + bool blockScroll; + bool shiftPressed; + bool newWindow; + bool fwdAvail; + bool backAvail; +}; + +QT_END_NAMESPACE + +#endif // HELPWINDOW_H diff --git a/tools/assistant/compat/images/assistant-128.png b/tools/assistant/compat/images/assistant-128.png Binary files differnew file mode 100644 index 0000000..f05949f --- /dev/null +++ b/tools/assistant/compat/images/assistant-128.png diff --git a/tools/assistant/compat/images/assistant.png b/tools/assistant/compat/images/assistant.png Binary files differnew file mode 100644 index 0000000..ea4d1e7 --- /dev/null +++ b/tools/assistant/compat/images/assistant.png diff --git a/tools/assistant/compat/images/close.png b/tools/assistant/compat/images/close.png Binary files differnew file mode 100644 index 0000000..540694e --- /dev/null +++ b/tools/assistant/compat/images/close.png diff --git a/tools/assistant/compat/images/designer.png b/tools/assistant/compat/images/designer.png Binary files differnew file mode 100644 index 0000000..72c42e7 --- /dev/null +++ b/tools/assistant/compat/images/designer.png diff --git a/tools/assistant/compat/images/linguist.png b/tools/assistant/compat/images/linguist.png Binary files differnew file mode 100644 index 0000000..d388cbd --- /dev/null +++ b/tools/assistant/compat/images/linguist.png diff --git a/tools/assistant/compat/images/mac/addtab.png b/tools/assistant/compat/images/mac/addtab.png Binary files differnew file mode 100644 index 0000000..20928fb --- /dev/null +++ b/tools/assistant/compat/images/mac/addtab.png diff --git a/tools/assistant/compat/images/mac/book.png b/tools/assistant/compat/images/mac/book.png Binary files differnew file mode 100644 index 0000000..7a3204c --- /dev/null +++ b/tools/assistant/compat/images/mac/book.png diff --git a/tools/assistant/compat/images/mac/closetab.png b/tools/assistant/compat/images/mac/closetab.png Binary files differnew file mode 100644 index 0000000..ab9d669 --- /dev/null +++ b/tools/assistant/compat/images/mac/closetab.png diff --git a/tools/assistant/compat/images/mac/editcopy.png b/tools/assistant/compat/images/mac/editcopy.png Binary files differnew file mode 100644 index 0000000..f551364 --- /dev/null +++ b/tools/assistant/compat/images/mac/editcopy.png diff --git a/tools/assistant/compat/images/mac/find.png b/tools/assistant/compat/images/mac/find.png Binary files differnew file mode 100644 index 0000000..3561745 --- /dev/null +++ b/tools/assistant/compat/images/mac/find.png diff --git a/tools/assistant/compat/images/mac/home.png b/tools/assistant/compat/images/mac/home.png Binary files differnew file mode 100644 index 0000000..78d94da --- /dev/null +++ b/tools/assistant/compat/images/mac/home.png diff --git a/tools/assistant/compat/images/mac/next.png b/tools/assistant/compat/images/mac/next.png Binary files differnew file mode 100644 index 0000000..a585cab --- /dev/null +++ b/tools/assistant/compat/images/mac/next.png diff --git a/tools/assistant/compat/images/mac/prev.png b/tools/assistant/compat/images/mac/prev.png Binary files differnew file mode 100644 index 0000000..612fb34 --- /dev/null +++ b/tools/assistant/compat/images/mac/prev.png diff --git a/tools/assistant/compat/images/mac/print.png b/tools/assistant/compat/images/mac/print.png Binary files differnew file mode 100644 index 0000000..10ca56c --- /dev/null +++ b/tools/assistant/compat/images/mac/print.png diff --git a/tools/assistant/compat/images/mac/synctoc.png b/tools/assistant/compat/images/mac/synctoc.png Binary files differnew file mode 100644 index 0000000..067fa94 --- /dev/null +++ b/tools/assistant/compat/images/mac/synctoc.png diff --git a/tools/assistant/compat/images/mac/whatsthis.png b/tools/assistant/compat/images/mac/whatsthis.png Binary files differnew file mode 100644 index 0000000..5b7078f --- /dev/null +++ b/tools/assistant/compat/images/mac/whatsthis.png diff --git a/tools/assistant/compat/images/mac/zoomin.png b/tools/assistant/compat/images/mac/zoomin.png Binary files differnew file mode 100644 index 0000000..d46f5af --- /dev/null +++ b/tools/assistant/compat/images/mac/zoomin.png diff --git a/tools/assistant/compat/images/mac/zoomout.png b/tools/assistant/compat/images/mac/zoomout.png Binary files differnew file mode 100644 index 0000000..4632656 --- /dev/null +++ b/tools/assistant/compat/images/mac/zoomout.png diff --git a/tools/assistant/compat/images/qt.png b/tools/assistant/compat/images/qt.png Binary files differnew file mode 100644 index 0000000..2dc6716 --- /dev/null +++ b/tools/assistant/compat/images/qt.png diff --git a/tools/assistant/compat/images/win/addtab.png b/tools/assistant/compat/images/win/addtab.png Binary files differnew file mode 100644 index 0000000..4bb0feb --- /dev/null +++ b/tools/assistant/compat/images/win/addtab.png diff --git a/tools/assistant/compat/images/win/book.png b/tools/assistant/compat/images/win/book.png Binary files differnew file mode 100644 index 0000000..09ec4d3 --- /dev/null +++ b/tools/assistant/compat/images/win/book.png diff --git a/tools/assistant/compat/images/win/closetab.png b/tools/assistant/compat/images/win/closetab.png Binary files differnew file mode 100644 index 0000000..ef9e020 --- /dev/null +++ b/tools/assistant/compat/images/win/closetab.png diff --git a/tools/assistant/compat/images/win/editcopy.png b/tools/assistant/compat/images/win/editcopy.png Binary files differnew file mode 100644 index 0000000..1121b47 --- /dev/null +++ b/tools/assistant/compat/images/win/editcopy.png diff --git a/tools/assistant/compat/images/win/find.png b/tools/assistant/compat/images/win/find.png Binary files differnew file mode 100644 index 0000000..6ea35e9 --- /dev/null +++ b/tools/assistant/compat/images/win/find.png diff --git a/tools/assistant/compat/images/win/home.png b/tools/assistant/compat/images/win/home.png Binary files differnew file mode 100644 index 0000000..b1c6ae1 --- /dev/null +++ b/tools/assistant/compat/images/win/home.png diff --git a/tools/assistant/compat/images/win/next.png b/tools/assistant/compat/images/win/next.png Binary files differnew file mode 100644 index 0000000..8df4127 --- /dev/null +++ b/tools/assistant/compat/images/win/next.png diff --git a/tools/assistant/compat/images/win/previous.png b/tools/assistant/compat/images/win/previous.png Binary files differnew file mode 100644 index 0000000..0780bc2 --- /dev/null +++ b/tools/assistant/compat/images/win/previous.png diff --git a/tools/assistant/compat/images/win/print.png b/tools/assistant/compat/images/win/print.png Binary files differnew file mode 100644 index 0000000..ba7c02d --- /dev/null +++ b/tools/assistant/compat/images/win/print.png diff --git a/tools/assistant/compat/images/win/synctoc.png b/tools/assistant/compat/images/win/synctoc.png Binary files differnew file mode 100644 index 0000000..da301bc --- /dev/null +++ b/tools/assistant/compat/images/win/synctoc.png diff --git a/tools/assistant/compat/images/win/whatsthis.png b/tools/assistant/compat/images/win/whatsthis.png Binary files differnew file mode 100644 index 0000000..623cad6 --- /dev/null +++ b/tools/assistant/compat/images/win/whatsthis.png diff --git a/tools/assistant/compat/images/win/zoomin.png b/tools/assistant/compat/images/win/zoomin.png Binary files differnew file mode 100644 index 0000000..2e586fc --- /dev/null +++ b/tools/assistant/compat/images/win/zoomin.png diff --git a/tools/assistant/compat/images/win/zoomout.png b/tools/assistant/compat/images/win/zoomout.png Binary files differnew file mode 100644 index 0000000..a736d39 --- /dev/null +++ b/tools/assistant/compat/images/win/zoomout.png diff --git a/tools/assistant/compat/images/wrap.png b/tools/assistant/compat/images/wrap.png Binary files differnew file mode 100644 index 0000000..90f18d9 --- /dev/null +++ b/tools/assistant/compat/images/wrap.png diff --git a/tools/assistant/compat/index.cpp b/tools/assistant/compat/index.cpp new file mode 100644 index 0000000..e98b00b --- /dev/null +++ b/tools/assistant/compat/index.cpp @@ -0,0 +1,581 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 new file mode 100644 index 0000000..9fc30af --- /dev/null +++ b/tools/assistant/compat/index.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 new file mode 100644 index 0000000..d4b5a47 --- /dev/null +++ b/tools/assistant/compat/lib/lib.pro @@ -0,0 +1,78 @@ +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)|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 new file mode 100644 index 0000000..25fbd6c --- /dev/null +++ b/tools/assistant/compat/lib/qassistantclient.cpp @@ -0,0 +1,447 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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. + + \inmodule QtAssistant + \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/lib/qassistantclient.h b/tools/assistant/compat/lib/qassistantclient.h new file mode 100644 index 0000000..d76246f --- /dev/null +++ b/tools/assistant/compat/lib/qassistantclient.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QASSISTANTCLIENT_H +#define QASSISTANTCLIENT_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 QTcpSocket; + +class QT_ASSISTANT_CLIENT_EXPORT QAssistantClient : public QObject +{ + Q_OBJECT + Q_PROPERTY( bool open READ isOpen ) + +public: + QAssistantClient( const QString &path, QObject *parent = 0); + ~QAssistantClient(); + + bool isOpen() const; + + void setArguments( const QStringList &args ); + +public Q_SLOTS: + virtual void openAssistant(); + virtual void closeAssistant(); + virtual void showPage( const QString &page ); + +Q_SIGNALS: + void assistantOpened(); + void assistantClosed(); + void error( const QString &msg ); + +private Q_SLOTS: + void socketConnected(); + void socketConnectionClosed(); + void readPort(); + void procError(QProcess::ProcessError err); + void socketError(); + void readStdError(); + +private: + QTcpSocket *socket; + QProcess *proc; + quint16 port; + QString host, assistantCommand, pageBuffer; + bool opened; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/tools/assistant/compat/lib/qassistantclient_global.h b/tools/assistant/compat/lib/qassistantclient_global.h new file mode 100644 index 0000000..3ae8bb2 --- /dev/null +++ b/tools/assistant/compat/lib/qassistantclient_global.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QASSISTANTCLIENT_GLOBAL_H +#define QASSISTANTCLIENT_GLOBAL_H + +#include <QtCore/qglobal.h> + +QT_BEGIN_HEADER + +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 + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/tools/assistant/compat/main.cpp b/tools/assistant/compat/main.cpp new file mode 100644 index 0000000..6609572 --- /dev/null +++ b/tools/assistant/compat/main.cpp @@ -0,0 +1,465 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 new file mode 100644 index 0000000..65759ad --- /dev/null +++ b/tools/assistant/compat/mainwindow.cpp @@ -0,0 +1,901 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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"))); +#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); +#if QT_EDITION == QT_EDITION_OPENSOURCE + QString edition = tr("Open Source Edition"); + QString info = tr("This version of Qt Assistant is part of the Qt Open Source Edition, for use " + "in the development of Open Source applications. " + "Qt is a comprehensive C++ framework for cross-platform application " + "development."); + QString moreInfo = tr("You need a commercial Qt license for development of proprietary (closed " + "source) applications. Please see <a href=\"http://qtsoftware.com/company/model" + "\">qtsoftware.com/company/model</a> for an overview of Qt licensing."); +#elif defined(QT_PRODUCT_LICENSE) + QString edition; + QString info; + QString moreInfo(tr("This program is licensed to you under the terms of the " + "Qt %1 License Agreement. For details, see the license file " + "that came with this software distribution.").arg(QLatin1String(QT_PRODUCT_LICENSE))); +#else + QString edition; + QString info; + QString moreInfo(tr("This program is licensed to you under the terms of the " + "Qt Commercial License Agreement. For details, see the file LICENSE " + "that came with this software distribution.")); + +#endif + + box.setText(QString::fromLatin1("<center><img src=\":/trolltech/assistant/images/assistant-128.png\">" + "<h3>%1</h3>" + "<p>Version %2 %3</p></center>" + "<p>%4</p>" + "<p>%5</p>" + "<p>Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).</p>" + "<p>The program is provided AS IS with NO WARRANTY OF ANY KIND," + " INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A" + " PARTICULAR PURPOSE.<p/>") + .arg(tr("Qt Assistant")).arg(QLatin1String(QT_VERSION_STR)).arg(edition).arg(info).arg(moreInfo)); + 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; +} + +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; + } +}; + +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 new file mode 100644 index 0000000..2073f0d --- /dev/null +++ b/tools/assistant/compat/mainwindow.h @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 new file mode 100644 index 0000000..803a4dc --- /dev/null +++ b/tools/assistant/compat/mainwindow.ui @@ -0,0 +1,459 @@ +<ui version="4.0" > + <comment>********************************************************************* +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +*********************************************************************</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 new file mode 100644 index 0000000..10b1737 --- /dev/null +++ b/tools/assistant/compat/profile.cpp @@ -0,0 +1,196 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 new file mode 100644 index 0000000..24aef3e --- /dev/null +++ b/tools/assistant/compat/profile.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 new file mode 100644 index 0000000..198be4a --- /dev/null +++ b/tools/assistant/compat/tabbedbrowser.cpp @@ -0,0 +1,530 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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(const QPoint&)), SLOT(openTabMenu(const 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(const 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 new file mode 100644 index 0000000..0e26bed --- /dev/null +++ b/tools/assistant/compat/tabbedbrowser.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 new file mode 100644 index 0000000..acb38f3 --- /dev/null +++ b/tools/assistant/compat/tabbedbrowser.ui @@ -0,0 +1,233 @@ +<ui version="4.0" > + <author></author> + <comment>********************************************************************* +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 new file mode 100644 index 0000000..7333cb3 --- /dev/null +++ b/tools/assistant/compat/topicchooser.cpp @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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.h b/tools/assistant/compat/topicchooser.h new file mode 100644 index 0000000..122a233 --- /dev/null +++ b/tools/assistant/compat/topicchooser.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TOPICCHOOSER_H +#define TOPICCHOOSER_H + +#include "ui_topicchooser.h" + +#include <QDialog> +#include <QStringList> + +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 + +QT_END_NAMESPACE diff --git a/tools/assistant/compat/topicchooser.ui b/tools/assistant/compat/topicchooser.ui new file mode 100644 index 0000000..a26eeb8 --- /dev/null +++ b/tools/assistant/compat/topicchooser.ui @@ -0,0 +1,162 @@ +<ui version="4.0" > + <comment>********************************************************************* +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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/compat/translations/translations.pro b/tools/assistant/compat/translations/translations.pro new file mode 100644 index 0000000..19fcc06 --- /dev/null +++ b/tools/assistant/compat/translations/translations.pro @@ -0,0 +1,34 @@ +# Include those manually as they do not contain any directory specification + +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 + +SOURCES += ../../../shared/fontpanel/fontpanel.cpp + +HEADERS += ../helpwindow.h \ + ../topicchooser.h \ + ../docuparser.h \ + ../index.h \ + ../profile.h \ + ../helpdialog.h \ + ../mainwindow.h \ + ../tabbedbrowser.h \ + ../config.h \ + ../fontsettingsdialog.h + + +TRANSLATIONS=$$[QT_INSTALL_TRANSLATIONS]/assistant_de.ts $$[QT_INSTALL_TRANSLATIONS]/assistant_untranslated.ts diff --git a/tools/assistant/lib/fulltextsearch/fulltextsearch.pri b/tools/assistant/lib/fulltextsearch/fulltextsearch.pri new file mode 100644 index 0000000..134678f --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/fulltextsearch.pri @@ -0,0 +1,161 @@ +DEFINES += _BUILD_FOR_QT_ LUCENE_DISABLE_MEMTRACKING +win32:DEFINES += _CRT_SECURE_NO_DEPRECATE _MT + +CLUCENEDIR = ../../../../src/3rdparty/clucene/src/CLucene + +INCLUDEPATH += . .. \ + $$CLUCENEDIR \ + $$CLUCENEDIR/../ \ + $$CLUCENEDIR/analysis \ + $$CLUCENEDIR/analysis/standard \ + $$CLUCENEDIR/config \ + $$CLUCENEDIR/debug \ + $$CLUCENEDIR/document \ + $$CLUCENEDIR/index \ + $$CLUCENEDIR/queryParser \ + $$CLUCENEDIR/search \ + $$CLUCENEDIR/store \ + $$CLUCENEDIR/util + + +SOURCES += $$CLUCENEDIR/StdHeader.cpp \ + $$CLUCENEDIR/analysis/AnalysisHeader.cpp \ + $$CLUCENEDIR/analysis/Analyzers.cpp \ + $$CLUCENEDIR/config/gunichartables.cpp \ + $$CLUCENEDIR/config/repl_lltot.cpp \ + $$CLUCENEDIR/config/repl_tcscasecmp.cpp \ + $$CLUCENEDIR/config/repl_tcslwr.cpp \ + $$CLUCENEDIR/config/repl_tcstod.cpp \ + $$CLUCENEDIR/config/repl_tcstoll.cpp \ + $$CLUCENEDIR/config/repl_tprintf.cpp \ + $$CLUCENEDIR/config/threads.cpp \ + $$CLUCENEDIR/config/utf8.cpp \ + $$CLUCENEDIR/debug/condition.cpp \ + $$CLUCENEDIR/debug/error.cpp \ + $$CLUCENEDIR/debug/memtracking.cpp \ + $$CLUCENEDIR/document/DateField.cpp \ + $$CLUCENEDIR/document/Document.cpp \ + $$CLUCENEDIR/document/Field.cpp \ + $$CLUCENEDIR/index/CompoundFile.cpp \ + $$CLUCENEDIR/index/DocumentWriter.cpp \ + $$CLUCENEDIR/index/FieldInfos.cpp \ + $$CLUCENEDIR/index/FieldsReader.cpp \ + $$CLUCENEDIR/index/FieldsWriter.cpp \ + $$CLUCENEDIR/index/IndexModifier.cpp \ + $$CLUCENEDIR/index/IndexReader.cpp \ + $$CLUCENEDIR/index/IndexWriter.cpp \ + $$CLUCENEDIR/index/MultiReader.cpp \ + $$CLUCENEDIR/index/SegmentInfos.cpp \ + $$CLUCENEDIR/index/SegmentMergeInfo.cpp \ + $$CLUCENEDIR/index/SegmentMergeQueue.cpp \ + $$CLUCENEDIR/index/SegmentMerger.cpp \ + $$CLUCENEDIR/index/SegmentReader.cpp \ + $$CLUCENEDIR/index/SegmentTermDocs.cpp \ + $$CLUCENEDIR/index/SegmentTermEnum.cpp \ + $$CLUCENEDIR/index/SegmentTermPositions.cpp \ + $$CLUCENEDIR/index/SegmentTermVector.cpp \ + $$CLUCENEDIR/index/Term.cpp \ + $$CLUCENEDIR/index/TermInfo.cpp \ + $$CLUCENEDIR/index/TermInfosReader.cpp \ + $$CLUCENEDIR/index/TermInfosWriter.cpp \ + $$CLUCENEDIR/index/TermVectorReader.cpp \ + $$CLUCENEDIR/index/TermVectorWriter.cpp \ + $$CLUCENEDIR/queryParser/Lexer.cpp \ + $$CLUCENEDIR/queryParser/MultiFieldQueryParser.cpp \ + $$CLUCENEDIR/queryParser/QueryParser.cpp \ + $$CLUCENEDIR/queryParser/QueryParserBase.cpp \ + $$CLUCENEDIR/queryParser/QueryToken.cpp \ + $$CLUCENEDIR/queryParser/TokenList.cpp \ + $$CLUCENEDIR/search/BooleanQuery.cpp \ + $$CLUCENEDIR/search/BooleanScorer.cpp \ + $$CLUCENEDIR/search/CachingWrapperFilter.cpp \ + $$CLUCENEDIR/search/ChainedFilter.cpp \ + $$CLUCENEDIR/search/ConjunctionScorer.cpp \ + $$CLUCENEDIR/search/DateFilter.cpp \ + $$CLUCENEDIR/search/ExactPhraseScorer.cpp \ + $$CLUCENEDIR/search/Explanation.cpp \ + $$CLUCENEDIR/search/FieldCache.cpp \ + $$CLUCENEDIR/search/FieldCacheImpl.cpp \ + $$CLUCENEDIR/search/FieldDocSortedHitQueue.cpp \ + $$CLUCENEDIR/search/FieldSortedHitQueue.cpp \ + $$CLUCENEDIR/search/FilteredTermEnum.cpp \ + $$CLUCENEDIR/search/FuzzyQuery.cpp \ + $$CLUCENEDIR/search/HitQueue.cpp \ + $$CLUCENEDIR/search/Hits.cpp \ + $$CLUCENEDIR/search/IndexSearcher.cpp \ + $$CLUCENEDIR/search/MultiSearcher.cpp \ + $$CLUCENEDIR/search/MultiTermQuery.cpp \ + $$CLUCENEDIR/search/PhrasePositions.cpp \ + $$CLUCENEDIR/search/PhraseQuery.cpp \ + $$CLUCENEDIR/search/PhraseScorer.cpp \ + $$CLUCENEDIR/search/PrefixQuery.cpp \ + $$CLUCENEDIR/search/QueryFilter.cpp \ + $$CLUCENEDIR/search/RangeFilter.cpp \ + $$CLUCENEDIR/search/RangeQuery.cpp \ + $$CLUCENEDIR/search/SearchHeader.cpp \ + $$CLUCENEDIR/search/Similarity.cpp \ + $$CLUCENEDIR/search/SloppyPhraseScorer.cpp \ + $$CLUCENEDIR/search/Sort.cpp \ + $$CLUCENEDIR/search/TermQuery.cpp \ + $$CLUCENEDIR/search/TermScorer.cpp \ + $$CLUCENEDIR/search/WildcardQuery.cpp \ + $$CLUCENEDIR/search/WildcardTermEnum.cpp \ + $$CLUCENEDIR/store/FSDirectory.cpp \ + $$CLUCENEDIR/store/IndexInput.cpp \ + $$CLUCENEDIR/store/IndexOutput.cpp \ + $$CLUCENEDIR/store/Lock.cpp \ + $$CLUCENEDIR/store/MMapInput.cpp \ + $$CLUCENEDIR/store/RAMDirectory.cpp \ + $$CLUCENEDIR/store/TransactionalRAMDirectory.cpp \ + $$CLUCENEDIR/util/BitSet.cpp \ + $$CLUCENEDIR/util/Equators.cpp \ + $$CLUCENEDIR/util/FastCharStream.cpp \ + $$CLUCENEDIR/util/fileinputstream.cpp \ + $$CLUCENEDIR/util/Misc.cpp \ + $$CLUCENEDIR/util/Reader.cpp \ + $$CLUCENEDIR/util/StringBuffer.cpp \ + $$CLUCENEDIR/util/StringIntern.cpp \ + $$CLUCENEDIR/util/ThreadLocal.cpp \ + $$CLUCENEDIR/analysis/standard/StandardAnalyzer.cpp \ + $$CLUCENEDIR/analysis/standard/StandardFilter.cpp \ + $$CLUCENEDIR/analysis/standard/StandardTokenizer.cpp + + +#Header files +HEADERS += qclucene_global_p.h \ + qclucene-config_p.h \ + qanalyzer_p.h \ + qtokenizer_p.h \ + qtoken_p.h \ + qtokenstream_p.h \ + qdocument_p.h \ + qfield_p.h \ + qindexreader_p.h \ + qindexwriter_p.h \ + qterm_p.h \ + qqueryparser_p.h \ + qfilter_p.h \ + qhits_p.h \ + qsearchable_p.h \ + qsort_p.h \ + qquery_p.h \ + qreader_p.h + + +#Source files +SOURCES += qanalyzer.cpp \ + qtokenizer.cpp \ + qtoken.cpp \ + qtokenstream.cpp \ + qdocument.cpp \ + qfield.cpp \ + qindexreader.cpp \ + qindexwriter.cpp \ + qterm.cpp \ + qqueryparser.cpp \ + qfilter.cpp \ + qhits.cpp \ + qsearchable.cpp \ + qsort.cpp \ + qquery.cpp \ + qreader.cpp diff --git a/tools/assistant/lib/fulltextsearch/fulltextsearch.pro b/tools/assistant/lib/fulltextsearch/fulltextsearch.pro new file mode 100644 index 0000000..e0cd13a --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/fulltextsearch.pro @@ -0,0 +1,50 @@ + +QMAKE_TARGET_PRODUCT = QtCLucene +QMAKE_TARGET_DESCRIPTION = QtCLucene full text search library wrapper. +#if qt is built with frameworks in debug, we must build QtCLucene in debug and release +#that's a similar logic as in qbase.pri +mac:!static:contains(QT_CONFIG, qt_framework) { + CONFIG(debug, debug|release) { + !build_pass:CONFIG += build_all + } +} +QT_CONFIG -= qt_framework +QT -= gui +TEMPLATE = lib +TARGET = QtCLucene +DEFINES += QHELP_LIB +include(../../../../src/qbase.pri) +include(fulltextsearch.pri) + +CONFIG += qt warn_off +contains(QT_CONFIG, reduce_exports) { + CONFIG += hide_symbols + # workaround for compiler errors on Ubuntu + linux*-g++*:DEFINES += _GLIBCXX_EXTERN_TEMPLATE=0 +} + +unix:QMAKE_PKGCONFIG_REQUIRES = QtCore + +# impossible to disable exceptions in clucene atm +CONFIG(exceptions_off) { + CONFIG -= exceptions_off + CONFIG += exceptions + !win32|win32-g++ { + QMAKE_CFLAGS -= -fno-exceptions + QMAKE_CXXFLAGS -= -fno-exceptions + QMAKE_LFLAGS -= -fno-exceptions + QMAKE_CFLAGS += -fexceptions + QMAKE_CXXFLAGS += -fexceptions + QMAKE_LFLAGS += -fexceptions + } +} + +win32-msvc.net | win32-msvc2* { + QMAKE_CFLAGS_RELEASE -= -O2 + QMAKE_CXXFLAGS_RELEASE -= -O2 +} + +# the following define could be set globally in case we need it elsewhere +solaris* { + DEFINES += Q_SOLARIS_VERSION=$$system(uname -r | sed -e 's/5\.//') +} diff --git a/tools/assistant/lib/fulltextsearch/license.txt b/tools/assistant/lib/fulltextsearch/license.txt new file mode 100644 index 0000000..9ef3d70 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/license.txt @@ -0,0 +1,503 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + diff --git a/tools/assistant/lib/fulltextsearch/qanalyzer.cpp b/tools/assistant/lib/fulltextsearch/qanalyzer.cpp new file mode 100644 index 0000000..e19a075 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qanalyzer.cpp @@ -0,0 +1,201 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qanalyzer_p.h" +#include "qclucene_global_p.h" + +#include <CLucene.h> +#include <CLucene/analysis/AnalysisHeader.h> + +QT_BEGIN_NAMESPACE + +QCLuceneAnalyzerPrivate::QCLuceneAnalyzerPrivate() + : QSharedData() +{ + analyzer = 0; + deleteCLuceneAnalyzer = true; +} + +QCLuceneAnalyzerPrivate::QCLuceneAnalyzerPrivate(const QCLuceneAnalyzerPrivate &other) + : QSharedData() +{ + analyzer = _CL_POINTER(other.analyzer); +} + +QCLuceneAnalyzerPrivate::~QCLuceneAnalyzerPrivate() +{ + if (deleteCLuceneAnalyzer) + _CLDECDELETE(analyzer); +} + + +QCLuceneAnalyzer::QCLuceneAnalyzer() + : d(new QCLuceneAnalyzerPrivate()) +{ + //nothing todo, private +} + +QCLuceneAnalyzer::~QCLuceneAnalyzer() +{ + // nothing todo +} + +qint32 QCLuceneAnalyzer::positionIncrementGap(const QString &fieldName) const +{ + Q_UNUSED(fieldName); + return 0; +} + +QCLuceneTokenStream QCLuceneAnalyzer::tokenStream(const QString &fieldName, + const QCLuceneReader &reader) const +{ + TCHAR *fName = QStringToTChar(fieldName); + QCLuceneTokenStream tokenStream; + tokenStream.d->tokenStream = d->analyzer->tokenStream(fName, reader.d->reader); + delete [] fName; + + return tokenStream; +} + + +QCLuceneStandardAnalyzer::QCLuceneStandardAnalyzer() + : QCLuceneAnalyzer() +{ + d->analyzer = new lucene::analysis::standard::StandardAnalyzer(); +} + +QCLuceneStandardAnalyzer::~QCLuceneStandardAnalyzer() +{ + // nothing todo +} + +QCLuceneStandardAnalyzer::QCLuceneStandardAnalyzer(const QStringList &stopWords) +{ + const TCHAR **tArray = new const TCHAR*[stopWords.count() +1]; + + for(int i = 0; i < stopWords.count(); ++i) { + TCHAR *stopWord = QStringToTChar(stopWords.at(i)); + tArray[i] = STRDUP_TtoT(stopWord); + delete [] stopWord; + } + tArray[stopWords.count()] = 0; + + d->analyzer = new lucene::analysis::standard::StandardAnalyzer(tArray); +} + + +QCLuceneWhitespaceAnalyzer::QCLuceneWhitespaceAnalyzer() + : QCLuceneAnalyzer() +{ + d->analyzer = new lucene::analysis::WhitespaceAnalyzer(); +} + +QCLuceneWhitespaceAnalyzer::~QCLuceneWhitespaceAnalyzer() +{ + // nothing todo +} + + +QCLuceneSimpleAnalyzer::QCLuceneSimpleAnalyzer() + : QCLuceneAnalyzer() +{ + d->analyzer = new lucene::analysis::SimpleAnalyzer(); +} + +QCLuceneSimpleAnalyzer::~QCLuceneSimpleAnalyzer() +{ + // nothing todo +} + + +QCLuceneStopAnalyzer::QCLuceneStopAnalyzer() + : QCLuceneAnalyzer() +{ + d->analyzer = new lucene::analysis::StopAnalyzer(); +} + +QCLuceneStopAnalyzer::~QCLuceneStopAnalyzer() +{ + // nothing todo +} + +QCLuceneStopAnalyzer::QCLuceneStopAnalyzer(const QStringList &stopWords) + : QCLuceneAnalyzer() +{ + const TCHAR **tArray = new const TCHAR*[stopWords.count() +1]; + + for(int i = 0; i < stopWords.count(); ++i) { + TCHAR *stopWord = QStringToTChar(stopWords.at(i)); + tArray[i] = STRDUP_TtoT(stopWord); + delete [] stopWord; + } + tArray[stopWords.count()] = 0; + + d->analyzer = new lucene::analysis::StopAnalyzer(tArray); +} + +QStringList QCLuceneStopAnalyzer::englishStopWords() const +{ + QStringList stopWordList; + + const TCHAR** stopWords = lucene::analysis::StopAnalyzer::ENGLISH_STOP_WORDS; + for (qint32 i = 0; stopWords[i] != 0; ++i) + stopWordList.append(TCharToQString(stopWords[i])); + + return stopWordList; +} + + +QCLuceneKeywordAnalyzer::QCLuceneKeywordAnalyzer() + : QCLuceneAnalyzer() +{ + d->analyzer = new lucene::analysis::KeywordAnalyzer(); +} + +QCLuceneKeywordAnalyzer::~QCLuceneKeywordAnalyzer() +{ + // nothing todo +} + + +QCLucenePerFieldAnalyzerWrapper::QCLucenePerFieldAnalyzerWrapper( + QCLuceneAnalyzer *defaultAnalyzer) + : QCLuceneAnalyzer() +{ + d->analyzer = new + lucene::analysis::PerFieldAnalyzerWrapper(defaultAnalyzer->d->analyzer); + + analyzers.append(defaultAnalyzer); + defaultAnalyzer->d->deleteCLuceneAnalyzer = false; +} + +QCLucenePerFieldAnalyzerWrapper::~QCLucenePerFieldAnalyzerWrapper() +{ + qDeleteAll(analyzers); +} + +void QCLucenePerFieldAnalyzerWrapper::addAnalyzer(const QString &fieldName, + QCLuceneAnalyzer *analyzer) +{ + lucene::analysis::PerFieldAnalyzerWrapper *analyzerWrapper = + static_cast<lucene::analysis::PerFieldAnalyzerWrapper*> (d->analyzer); + + if (analyzerWrapper == 0) + return; + + analyzers.append(analyzer); + analyzer->d->deleteCLuceneAnalyzer = false; + + TCHAR *fName = QStringToTChar(fieldName); + analyzerWrapper->addAnalyzer(fName, analyzer->d->analyzer); + delete [] fName; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qanalyzer_p.h b/tools/assistant/lib/fulltextsearch/qanalyzer_p.h new file mode 100644 index 0000000..c0b94f4 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qanalyzer_p.h @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QANALYZER_P_H +#define QANALYZER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qreader_p.h" +#include "qtokenstream_p.h" +#include "qclucene_global_p.h" + +#include <QtCore/QList> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(analysis) + class Analyzer; +CL_NS_END +CL_NS_USE(analysis) + +QT_BEGIN_NAMESPACE + +class QCLuceneIndexWriter; +class QCLuceneQueryParser; +class QCLuceneStopAnalyzer; +class QCLuceneSimpleAnalyzer; +class QCLuceneKeywordAnalyzer; +class QCLuceneStandardAnalyzer; +class QCLuceneWhitespaceAnalyzer; +class QCLucenePerFieldAnalyzerWrapper; + +class QHELP_EXPORT QCLuceneAnalyzerPrivate : public QSharedData +{ +public: + QCLuceneAnalyzerPrivate(); + QCLuceneAnalyzerPrivate(const QCLuceneAnalyzerPrivate &other); + + ~QCLuceneAnalyzerPrivate(); + + Analyzer *analyzer; + bool deleteCLuceneAnalyzer; + +private: + QCLuceneAnalyzerPrivate &operator=(const QCLuceneAnalyzerPrivate &other); +}; + +class QHELP_EXPORT QCLuceneAnalyzer +{ +public: + virtual ~QCLuceneAnalyzer(); + + qint32 positionIncrementGap(const QString &fieldName) const; + QCLuceneTokenStream tokenStream(const QString &fieldName, + const QCLuceneReader &reader) const; + +protected: + friend class QCLuceneIndexWriter; + friend class QCLuceneQueryParser; + friend class QCLuceneStopAnalyzer; + friend class QCLuceneSimpleAnalyzer; + friend class QCLuceneKeywordAnalyzer; + friend class QCLuceneStandardAnalyzer; + friend class QCLuceneWhitespaceAnalyzer; + friend class QCLucenePerFieldAnalyzerWrapper; + QSharedDataPointer<QCLuceneAnalyzerPrivate> d; + +private: + QCLuceneAnalyzer(); +}; + +class QHELP_EXPORT QCLuceneStandardAnalyzer : public QCLuceneAnalyzer +{ +public: + QCLuceneStandardAnalyzer(); + QCLuceneStandardAnalyzer(const QStringList &stopWords); + + ~QCLuceneStandardAnalyzer(); +}; + +class QHELP_EXPORT QCLuceneWhitespaceAnalyzer : public QCLuceneAnalyzer +{ +public: + QCLuceneWhitespaceAnalyzer(); + ~QCLuceneWhitespaceAnalyzer(); +}; + +class QHELP_EXPORT QCLuceneSimpleAnalyzer : public QCLuceneAnalyzer +{ +public: + QCLuceneSimpleAnalyzer(); + ~QCLuceneSimpleAnalyzer(); +}; + +class QHELP_EXPORT QCLuceneStopAnalyzer : public QCLuceneAnalyzer +{ +public: + QCLuceneStopAnalyzer(); + QCLuceneStopAnalyzer(const QStringList &stopWords); + + ~QCLuceneStopAnalyzer(); + + QStringList englishStopWords() const; +}; + +class QHELP_EXPORT QCLuceneKeywordAnalyzer : public QCLuceneAnalyzer +{ +public: + QCLuceneKeywordAnalyzer(); + ~QCLuceneKeywordAnalyzer(); +}; + +class QHELP_EXPORT QCLucenePerFieldAnalyzerWrapper : public QCLuceneAnalyzer +{ +public: + QCLucenePerFieldAnalyzerWrapper(QCLuceneAnalyzer *defaultAnalyzer); + ~QCLucenePerFieldAnalyzerWrapper(); + + void addAnalyzer(const QString &fieldName, QCLuceneAnalyzer *analyzer); + +private: + QList<QCLuceneAnalyzer*> analyzers; +}; + +QT_END_NAMESPACE + +#endif // QANALYZER_P_H diff --git a/tools/assistant/lib/fulltextsearch/qclucene-config_p.h b/tools/assistant/lib/fulltextsearch/qclucene-config_p.h new file mode 100644 index 0000000..b3befbe --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qclucene-config_p.h @@ -0,0 +1,552 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QCLUCENE_CONFIG_P_H +#define QCLUCENE_CONFIG_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> + +#ifndef _SRC_CLUCENE_CLUCENE_CONFIG_H +#define _SRC_CLUCENE_CLUCENE_CONFIG_H 1 + +/* +src/CLucene/clucene-config.h. +Generated +automatically +at +end +of +configure. +*/ +/* config.h.tmp. Generated by configure. */ +/* config.h.tmp.in. Generated from configure.ac by autoheader. */ + +/* Disable multithreading */ +/* #undef _CL_DISABLE_MULTITHREADING */ + +/* Define to 1 if you have the <algorithm> header file. */ +#ifndef _CL_HAVE_ALGORITHM +#define _CL_HAVE_ALGORITHM 1 +#endif + +/* Define to 1 if you have the <ctype.h> header file. */ +#ifndef _CL_HAVE_CTYPE_H +#define _CL_HAVE_CTYPE_H 1 +#endif + +/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'. + */ +#ifndef _CL_HAVE_DIRENT_H +#define _CL_HAVE_DIRENT_H 1 +#endif + +#if !defined (__MINGW32__) + /* Define to 1 if you have the <dlfcn.h> header file. */ +# ifndef _CL_HAVE_DLFCN_H +# define _CL_HAVE_DLFCN_H 1 +# endif +#endif + +/* Define to 1 if you have the <errno.h> header file. */ +#ifndef _CL_HAVE_ERRNO_H +#define _CL_HAVE_ERRNO_H 1 +#endif + +#if !defined(__SUNPRO_CC) && !defined(__SUNPRO_C) + /* Define to 1 if you have the <ext/hash_map> header file. */ +# ifndef _CL_HAVE_EXT_HASH_MAP +# define _CL_HAVE_EXT_HASH_MAP 1 +# endif + + /* Define to 1 if you have the <ext/hash_set> header file. */ +# ifndef _CL_HAVE_EXT_HASH_SET +# define _CL_HAVE_EXT_HASH_SET 1 +# endif +#endif + +/* Define to 1 if you have the <fcntl.h> header file. */ +#ifndef _CL_HAVE_FCNTL_H +#define _CL_HAVE_FCNTL_H 1 +#endif + +#if !defined(__xlC__) && !defined(__xlc__) && !defined (__MINGW32__) && \ + !defined(__HP_aCC) && !defined(__SUNPRO_C) && !defined(__SUNPRO_CC) || \ + defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x550) || (defined(__HP_aCC) && defined(__ia64)) + /* Define to 1 if the system has the type `float_t'. */ +# ifndef _CL_HAVE_FLOAT_T +# define _CL_HAVE_FLOAT_T 1 +# endif +#endif + +/* Define to 1 if you have the <functional> header file. */ +#ifndef _CL_HAVE_FUNCTIONAL +#define _CL_HAVE_FUNCTIONAL 1 +#endif + +/* Does not support new float byte<->float conversions */ +#ifndef _CL_HAVE_FUNCTIONING_FLOAT_BYTE +#define _CL_HAVE_FUNCTIONING_FLOAT_BYTE +#endif + +/* Define to 1 if you have the `getpagesize' function. */ +#ifndef _CL_HAVE_GETPAGESIZE +#define _CL_HAVE_GETPAGESIZE 1 +#endif + +/* Define to 1 if you have the <hash_map> header file. */ +/* #undef _CL_HAVE_HASH_MAP */ + +/* Define to 1 if you have the <hash_set> header file. */ +/* #undef _CL_HAVE_HASH_SET */ + +/* Define to 1 if the system has the type `intptr_t'. */ +#ifndef _CL_HAVE_INTPTR_T +#define _CL_HAVE_INTPTR_T 1 +#endif + +/* Define to 1 if you have the <inttypes.h> header file. */ +#ifndef _CL_HAVE_INTTYPES_H +#define _CL_HAVE_INTTYPES_H 1 +#endif + +/* Define to 1 if you have the <list> header file. */ +#ifndef _CL_HAVE_LIST +#define _CL_HAVE_LIST 1 +#endif + +/* Define to 1 if you have the `lltoa' function. */ +/* #undef _CL_HAVE_LLTOA */ + +#if defined(__MINGW32__) + /* Define to 1 if you have the `lltow' function. */ +# ifndef _CL_HAVE_LLTOW +# define _CL_HAVE_LLTOW 1 +# endif +#endif + +#if !defined(__SUNPRO_CC) && !defined(__SUNPRO_C) && !defined(__xlC__) && !defined(__xlc__) + /* Define to 1 if long double works and has more range or precision than double. */ +# ifndef _CL_HAVE_LONG_DOUBLE +# define _CL_HAVE_LONG_DOUBLE 1 +# endif +#endif + +/* Define to 1 if you have the <map> header file. */ +#ifndef _CL_HAVE_MAP +#define _CL_HAVE_MAP 1 +#endif + +/* Define to 1 if you have the <math.h> header file. */ +#ifndef _CL_HAVE_MATH_H +#define _CL_HAVE_MATH_H 1 +#endif + +/* Define to 1 if you have the <memory.h> header file. */ +#ifndef _CL_HAVE_MEMORY_H +#define _CL_HAVE_MEMORY_H 1 +#endif + +#if !defined(__MINGW32__) && !defined(__HP_aCC) && !defined(__xlC__) && !defined(__xlc__) + /* Define to 1 if you have a working `mmap' system call. */ +# ifndef _CL_HAVE_MMAP +# define _CL_HAVE_MMAP 1 +# endif +#endif + +/* define if the compiler implements namespaces */ +#ifndef _CL_HAVE_NAMESPACES +#define _CL_HAVE_NAMESPACES +#endif + +#if defined(__SUNPRO_CC) || defined(__SUNPRO_C) || defined(__HP_aCC) || defined(__xlC__) || defined(__xlc__) + /* Define if you have the nanosleep function */ +# ifndef _CL_HAVE_NANOSLEEP +# define _CL_HAVE_NANOSLEEP 1 +# endif +#endif + +/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */ +/* #undef _CL_HAVE_NDIR_H */ + +/* Does not support new float byte<->float conversions */ +/* #undef _CL_HAVE_NO_FLOAT_BYTE */ + +/* Does not support try/catch blocks */ +/* #undef _CL_HAVE_NO_FUNCTION_TRY_BLOCKS */ + +/* Define to 1 if you have the `printf' function. */ +#ifndef _CL_HAVE_PRINTF +#define _CL_HAVE_PRINTF 1 +#endif + +#if !defined(__MINGW32__) + /* Define if you have POSIX threads libraries and header files. */ +# ifndef _CL_HAVE_PTHREAD +# define _CL_HAVE_PTHREAD 1 +# endif +#endif + +/* Define if recursive pthread mutexes are available */ +/* #undef _CL_HAVE_PTHREAD_MUTEX_RECURSIVE */ + +/* Define to 1 if you have the <set> header file. */ +#ifndef _CL_HAVE_SET +#define _CL_HAVE_SET 1 +#endif + +/* Define to 1 if you have the `snprintf' function. */ +#ifndef _CL_HAVE_SNPRINTF +#define _CL_HAVE_SNPRINTF 1 +#endif + +/* Defined if the snprintf overflow test fails */ +/* #undef _CL_HAVE_SNPRINTF_BUG */ + +/* Define to 1 if you have the `snwprintf' function. */ +/* #undef _CL_HAVE_SNWPRINTF */ + +#if !defined(__HP_aCC) && !defined(__SUNPRO_CC) && !defined(__SUNPRO_C) + /* define if the compiler supports ISO C++ standard library */ +# ifndef _CL_HAVE_STD +# define _CL_HAVE_STD +# endif +#endif + +/* Define to 1 if you have the <stdarg.h> header file. */ +#ifndef _CL_HAVE_STDARG_H +#define _CL_HAVE_STDARG_H 1 +#endif + +/* x */ +#ifndef _CL_HAVE_STDEXCEPT +#define _CL_HAVE_STDEXCEPT +#endif + +#if !defined(__SUNPRO_CC) && !defined(__SUNPRO_C) && !defined(__HP_aCC) && \ + !defined(__xlC__) && !defined(__xlc__) + /* Define to 1 if you have the <stdint.h> header file. */ +# ifndef _CL_HAVE_STDINT_H +# define _CL_HAVE_STDINT_H 1 +# endif +#endif + +#if !defined(__HP_aCC) + /* Define to 1 if you have the <stdlib.h> header file. */ +# ifndef _CL_HAVE_STDLIB_H +# define _CL_HAVE_STDLIB_H 1 +# endif + + /* define if the compiler supports Standard Template Library */ +# ifndef _CL_HAVE_STL +# define _CL_HAVE_STL +# endif +#endif + +/* Define to 1 if you have the <strings.h> header file. */ +#ifndef _CL_HAVE_STRINGS_H +#define _CL_HAVE_STRINGS_H 1 +#endif + +/* Define to 1 if you have the <string.h> header file. */ +#ifndef _CL_HAVE_STRING_H +#define _CL_HAVE_STRING_H 1 +#endif + +/* Define to 1 if you have the `strlwr' function. */ +/* #undef _CL_HAVE_STRLWR */ + +/* Define to 1 if you have the `strtoll' function. */ +/* #undef _CL_HAVE_STRTOLL */ + +/* Define to 1 if you have the `strupr' function. */ +/* #undef _CL_HAVE_STRUPR */ + +/* Defined if the swprintf test fails */ +#ifndef _CL_HAVE_SWPRINTF_BUG +#define _CL_HAVE_SWPRINTF_BUG +#endif + +/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'. + */ +/* #undef _CL_HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'. + */ +/* #undef _CL_HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#ifndef _CL_HAVE_SYS_STAT_H +#define _CL_HAVE_SYS_STAT_H 1 +#endif + +/* Define to 1 if you have the <sys/timeb.h> header file. */ +#ifndef _CL_HAVE_SYS_TIMEB_H +#define _CL_HAVE_SYS_TIMEB_H 1 +#endif + +/* Define to 1 if you have the <sys/types.h> header file. */ +#ifndef _CL_HAVE_SYS_TYPES_H +#define _CL_HAVE_SYS_TYPES_H 1 +#endif + +// Do not use the tchar.h that ships with mingw, this causes the qt build to +// fail (211547, 211401, etc...), reuse the replacement as with any other compiler +// #if defined(__MINGW32__) +// /* Define to 1 if you have the <tchar.h> header file. */ +// # ifndef _CL_HAVE_TCHAR_H +// # define _CL_HAVE_TCHAR_H 1 +// # endif +// #endif + +#if defined(__MINGW32__) || defined(__SUNPRO_CC) || defined(__SUNPRO_C) + /* Define to 1 if you have the `tell' function. */ +# ifndef _CL_HAVE_TELL +# define _CL_HAVE_TELL 1 +# endif +#endif + +/* Define to 1 if you have the <unistd.h> header file. */ +#ifndef _CL_HAVE_UNISTD_H +#define _CL_HAVE_UNISTD_H 1 +#endif + +/* Define to 1 if you have the <vector> header file. */ +#ifndef _CL_HAVE_VECTOR +#define _CL_HAVE_VECTOR 1 +#endif + +/* Define to 1 if you have the `vsnwprintf' function. */ +/* #undef _CL_HAVE_VSNWPRINTF */ + +/* Define to 1 if you have the <wchar.h> header file. */ +#ifndef _CL_HAVE_WCHAR_H +#define _CL_HAVE_WCHAR_H 1 +#endif + +/* Define to 1 if the system has the type `wchar_t'. */ +#ifndef _CL_HAVE_WCHAR_T +#define _CL_HAVE_WCHAR_T 1 +#endif + +#if !defined(__SUNPRO_CC) && !defined(__SUNPRO_C) && !defined(__MINGW32__) && \ + !defined(Q_OS_MAC) && !defined(__HP_aCC) + /* Define to 1 if you have the `wcscasecmp' function. */ +# ifndef _CL_HAVE_WCSCASECMP +# define _CL_HAVE_WCSCASECMP 1 +# endif +#endif + +/* Define to 1 if you have the `wcscat' function. */ +#ifndef _CL_HAVE_WCSCAT +#define _CL_HAVE_WCSCAT 1 +#endif + +/* Define to 1 if you have the `wcschr' function. */ +#ifndef _CL_HAVE_WCSCHR +#define _CL_HAVE_WCSCHR 1 +#endif + +/* Define to 1 if you have the `wcscmp' function. */ +#ifndef _CL_HAVE_WCSCMP +#define _CL_HAVE_WCSCMP 1 +#endif + +/* Define to 1 if you have the `wcscpy' function. */ +#ifndef _CL_HAVE_WCSCPY +#define _CL_HAVE_WCSCPY 1 +#endif + +/* Define to 1 if you have the `wcscspn' function. */ +#ifndef _CL_HAVE_WCSCSPN +#define _CL_HAVE_WCSCSPN 1 +#endif + +#if defined(__MINGW32__) + /* Define to 1 if you have the `wcsicmp' function. */ +# ifndef _CL_HAVE_WCSICMP +# define _CL_HAVE_WCSICMP 1 +# endif +#endif + +/* Define to 1 if you have the `wcslen' function. */ +#ifndef _CL_HAVE_WCSLEN +#define _CL_HAVE_WCSLEN 1 +#endif + +/* Define to 1 if you have the `wcsncmp' function. */ +#ifndef _CL_HAVE_WCSNCMP +#define _CL_HAVE_WCSNCMP 1 +#endif + +/* Define to 1 if you have the `wcsncpy' function. */ +#ifndef _CL_HAVE_WCSNCPY +#define _CL_HAVE_WCSNCPY 1 +#endif + +/* Define to 1 if you have the `wcsstr' function. */ +#ifndef _CL_HAVE_WCSSTR +#define _CL_HAVE_WCSSTR 1 +#endif + +/* Define to 1 if you have the `wcstod' function. */ +#ifndef _CL_HAVE_WCSTOD +#define _CL_HAVE_WCSTOD 1 +#endif + +#if !defined(__SUNPRO_CC) && !defined(__SUNPRO_C) && !defined(__HP_aCC) + /* Define to 1 if you have the `wcstoll' function. */ +# ifndef _CL_HAVE_WCSTOLL +# define _CL_HAVE_WCSTOLL 1 +# endif +#endif + +#if defined(__MINGW32__) + /* Define to 1 if you have the `wcsupr' function. */ +# ifndef _CL_HAVE_WCSUPR +# define _CL_HAVE_WCSUPR 1 +# endif +#endif + +#if defined(__SUNPRO_CC) || defined(__SUNPRO_C) || defined(__HP_aCC) + /* Define to 1 if you have a functioning <wchar.h> header file. */ +# ifndef _CL_HAVE_WCTYPE_H +# define _CL_HAVE_WCTYPE_H +# endif +#endif + +/* Define to 1 if you have the `wprintf' function. */ +/* #undef _CL_HAVE_WPRINTF */ + +#if defined(__MINGW32__) + /* Define to 1 if you have the `_filelength' function. */ +# ifndef _CL_HAVE__FILELENGTH +# define _CL_HAVE__FILELENGTH 1 +# endif +#endif + +/* How to define a static const in a class */ +#ifndef LUCENE_STATIC_CONSTANT_SYNTAX +#define LUCENE_STATIC_CONSTANT_SYNTAX 1 +#endif + +/* Name of package */ +#ifndef _CL_PACKAGE +#define _CL_PACKAGE "clucene-core" +#endif + +/* Define to the address where bug reports for this package should be sent. */ +#ifndef _CL_PACKAGE_BUGREPORT +#define _CL_PACKAGE_BUGREPORT "" +#endif + +/* Define to the full name of this package. */ +#ifndef _CL_PACKAGE_NAME +#define _CL_PACKAGE_NAME "" +#endif + +/* Define to the full name and version of this package. */ +#ifndef _CL_PACKAGE_STRING +#define _CL_PACKAGE_STRING "" +#endif + +/* Define to the one symbol short name of this package. */ +#ifndef _CL_PACKAGE_TARNAME +#define _CL_PACKAGE_TARNAME "" +#endif + +/* Define to the version of this package. */ +#ifndef _CL_PACKAGE_VERSION +#define _CL_PACKAGE_VERSION "" +#endif + +/* Define to the necessary symbol if this constant uses a non-standard name on + your system. */ +/* #undef _CL_PTHREAD_CREATE_JOINABLE */ + +/* The size of a `unsigned char', as computed by sizeof. */ +/* #undef _CL_SIZEOF_UNSIGNED_CHAR */ + +/* The size of a `unsigned int', as computed by sizeof. */ +/* #undef _CL_SIZEOF_UNSIGNED_INT */ + +/* The size of a `unsigned long', as computed by sizeof. */ +/* #undef _CL_SIZEOF_UNSIGNED_LONG */ + +/* The size of a `unsigned long long', as computed by sizeof. */ +/* #undef _CL_SIZEOF_UNSIGNED_LONG_LONG */ + +/* The size of a `unsigned __int64', as computed by sizeof. */ +/* #undef _CL_SIZEOF_UNSIGNED___INT64 */ + +/* Define to 1 if the `S_IS*' macros in <sys/stat.h> do not work properly. */ +/* #undef _CL_STAT_MACROS_BROKEN */ + +#if !defined(__HP_aCC) + /* Define to 1 if you have the ANSI C header files. */ +# ifndef _CL_STDC_HEADERS +# define _CL_STDC_HEADERS 1 +# endif + +/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */ +# ifndef _CL_TIME_WITH_SYS_TIME +# define _CL_TIME_WITH_SYS_TIME 1 +# endif +#endif + +/* Version number of package */ +#ifndef _CL_VERSION +#define _CL_VERSION "0.9.17" +#endif + +/* Forces into Ascii mode */ +/* #undef _ASCII */ + +/* Conditional Debugging */ +/* #undef _CL__CND_DEBUG */ + +/* debuging option */ +/* #undef _DEBUG */ + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* If not already defined, then define as a datatype of *exactly* 32 bits. */ +/* #undef uint32_t */ + +/* If not already defined, then define as a datatype of *exactly* 64 bits. */ +/* #undef uint64_t */ + +/* If not already defined, then define as a datatype of *exactly* 8 bits. */ +/* #undef uint8_t */ + +/* once: +_SRC_CLUCENE_CLUCENE_CONFIG_H +*/ +#endif + + +#if defined Q_CC_MSVC && _MSC_VER < 1300 +# define LUCENE_NO_STDC_NAMESPACE +#endif + + +#endif // QCLUCENE_CONFIG_P_H + diff --git a/tools/assistant/lib/fulltextsearch/qclucene_global_p.h b/tools/assistant/lib/fulltextsearch/qclucene_global_p.h new file mode 100644 index 0000000..2a9d146 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qclucene_global_p.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QCLUCENE_GLOBAL_P_H +#define QCLUCENE_GLOBAL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#if !defined(_MSC_VER) +# include "qclucene-config_p.h" +#endif + +#include <QtCore/QChar> +#include <QtCore/QString> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +#if !defined(QT_SHARED) && !defined(QT_DLL) +# define QHELP_EXPORT +#elif defined(QHELP_LIB) +# define QHELP_EXPORT Q_DECL_EXPORT +#else +# define QHELP_EXPORT Q_DECL_IMPORT +#endif + +// +// W A R N I N G +// ------------- +// +// adjustments here, need to be done in +// QTDIR/src/3rdparty/clucene/src/CLucene/StdHeader.h as well +// +#if defined(_LUCENE_DONTIMPLEMENT_NS_MACROS) + +#elif !defined(DISABLE_NAMESPACE) +# ifdef QT_NAMESPACE +# define CL_NS_DEF(sub) namespace QT_NAMESPACE { namespace lucene{ namespace sub{ +# define CL_NS_DEF2(sub,sub2) namespace QT_NAMESPACE { namespace lucene{ namespace sub{ namespace sub2 { + +# define CL_NS_END }}} +# define CL_NS_END2 }}}} + +# define CL_NS_USE(sub) using namespace QT_NAMESPACE::lucene::sub; +# define CL_NS_USE2(sub,sub2) using namespace QT_NAMESPACE::lucene::sub::sub2; + +# define CL_NS(sub) QT_NAMESPACE::lucene::sub +# define CL_NS2(sub,sub2) QT_NAMESPACE::lucene::sub::sub2 +# else +# define CL_NS_DEF(sub) namespace lucene{ namespace sub{ +# define CL_NS_DEF2(sub,sub2) namespace lucene{ namespace sub{ namespace sub2 { + +# define CL_NS_END }} +# define CL_NS_END2 }}} + +# define CL_NS_USE(sub) using namespace lucene::sub; +# define CL_NS_USE2(sub,sub2) using namespace lucene::sub::sub2; + +# define CL_NS(sub) lucene::sub +# define CL_NS2(sub,sub2) lucene::sub::sub2 +# endif +#else +# define CL_NS_DEF(sub) +# define CL_NS_DEF2(sub, sub2) +# define CL_NS_END +# define CL_NS_END2 +# define CL_NS_USE(sub) +# define CL_NS_USE2(sub,sub2) +# define CL_NS(sub) +# define CL_NS2(sub,sub2) +#endif + +#if !defined(_MSC_VER) && defined(_CL_HAVE_WCHAR_H) && defined(_CL_HAVE_WCHAR_T) +# if !defined(TCHAR) +# define TCHAR wchar_t +# endif +#else +# include <windows.h> +#endif + +namespace { + TCHAR* QStringToTChar(const QString &str) + { + TCHAR *string = new TCHAR[(str.length() +1) * sizeof(TCHAR)]; + memset(string, 0, (str.length() +1) * sizeof(TCHAR)); + #if defined(UNICODE) || defined(_CL_HAVE_WCHAR_H) && defined(_CL_HAVE_WCHAR_T) + str.toWCharArray(string); + #else + const QByteArray ba = str.toAscii(); + strcpy(string, ba.constData()); + #endif + return string; + } + + QString TCharToQString(const TCHAR *string) + { + #if defined(UNICODE) || defined(_CL_HAVE_WCHAR_H) && defined(_CL_HAVE_WCHAR_T) + QString retValue = QString::fromWCharArray(string); + return retValue; + #else + return QString(QLatin1String(string)); + #endif + } +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QCLUCENE_GLOBAL_P_H diff --git a/tools/assistant/lib/fulltextsearch/qdocument.cpp b/tools/assistant/lib/fulltextsearch/qdocument.cpp new file mode 100644 index 0000000..7e0f6d9 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qdocument.cpp @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qdocument_p.h" +#include "qreader_p.h" +#include "qclucene_global_p.h" + +#include <CLucene.h> +#include <CLucene/util/Reader.h> +#include <CLucene/document/Document.h> + +QT_BEGIN_NAMESPACE + +QCLuceneDocumentPrivate::QCLuceneDocumentPrivate() + : QSharedData() +{ + document = 0; + deleteCLuceneDocument = true; +} + +QCLuceneDocumentPrivate::QCLuceneDocumentPrivate(const QCLuceneDocumentPrivate &other) + : QSharedData() +{ + document = _CL_POINTER(other.document); +} + +QCLuceneDocumentPrivate::~QCLuceneDocumentPrivate() +{ + if (deleteCLuceneDocument) + _CLDECDELETE(document); +} + + +QCLuceneDocument::QCLuceneDocument() + : d(new QCLuceneDocumentPrivate()) +{ + // nothing todo + d->document = new lucene::document::Document(); +} + +QCLuceneDocument::~QCLuceneDocument() +{ + qDeleteAll(fieldList); + fieldList.clear(); +} + +void QCLuceneDocument::add(QCLuceneField *field) +{ + field->d->deleteCLuceneField = false; + d->document->add(*field->d->field); + fieldList.append(field); +} + +QCLuceneField* QCLuceneDocument::getField(const QString &name) const +{ + QCLuceneField* field = 0; + foreach (field, fieldList) { + if (field->name() == name && field->d->field != 0) + return field; + } + + field = 0; + TCHAR *fieldName = QStringToTChar(name); + lucene::document::Field *f = d->document->getField(fieldName); + if (f) { + field = new QCLuceneField(); + field->d->field = f; + fieldList.append(field); + field->d->deleteCLuceneField = false; + + lucene::util::Reader *r = f->readerValue(); + if (r) { + field->reader->d->reader = r; + field->reader->d->deleteCLuceneReader = false; + } + } + delete [] fieldName; + + return field; +} + +QString QCLuceneDocument::get(const QString &name) const +{ + QCLuceneField* field = getField(name); + if (field) + return field->stringValue(); + + return QString(); +} + +QString QCLuceneDocument::toString() const +{ + return TCharToQString(d->document->toString()); +} + +void QCLuceneDocument::setBoost(qreal boost) +{ + d->document->setBoost(qreal(boost)); +} + +qreal QCLuceneDocument::getBoost() const +{ + return qreal(d->document->getBoost()); +} + +void QCLuceneDocument::removeField(const QString &name) +{ + TCHAR *fieldName = QStringToTChar(name); + d->document->removeField(fieldName); + delete [] fieldName; + + QList<QCLuceneField*> tmp; + lucene::document::DocumentFieldEnumeration *dfe = d->document->fields(); + while (dfe->hasMoreElements()) { + const lucene::document::Field* f = dfe->nextElement(); + foreach (QCLuceneField* field, fieldList) { + if (f == field->d->field) { + tmp.append(field); + break; + } + } + } + _CLDELETE(dfe); + fieldList = tmp; +} + +void QCLuceneDocument::removeFields(const QString &name) +{ + for (qint32 i = fieldList.count() -1; i >= 0; --i) { + QCLuceneField* field = fieldList.at(i); + if (field->name() == name) + delete fieldList.takeAt(i); + } + + TCHAR *fieldName = QStringToTChar(name); + d->document->removeFields(fieldName); + delete [] fieldName; +} + +QStringList QCLuceneDocument::getValues(const QString &name) const +{ + TCHAR *fieldName = QStringToTChar(name); + TCHAR **values = d->document->getValues(fieldName); + + QStringList retValue; + if (values) { + for (qint32 i = 0; 0 != values[i]; ++i) { + retValue.append(TCharToQString((const TCHAR*)values[i])); + delete [] values[i]; values[i] = 0; + } + delete values; + } + + delete [] fieldName; + return retValue; +} + +void QCLuceneDocument::clear() +{ + d->document->clear(); + qDeleteAll(fieldList); + fieldList.clear(); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qdocument_p.h b/tools/assistant/lib/fulltextsearch/qdocument_p.h new file mode 100644 index 0000000..45f3d00 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qdocument_p.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QDOCUMENT_P_H +#define QDOCUMENT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qfield_p.h" +#include "qclucene_global_p.h" + +#include <QtCore/QList> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(document) + class Document; +CL_NS_END +CL_NS_USE(document) + +QT_BEGIN_NAMESPACE + +class QCLuceneHits; +class QCLuceneIndexReader; +class QCLuceneIndexWriter; +class QCLuceneIndexSearcher; +class QCLuceneMultiSearcher; + +class QHELP_EXPORT QCLuceneDocumentPrivate : public QSharedData +{ +public: + QCLuceneDocumentPrivate(); + QCLuceneDocumentPrivate(const QCLuceneDocumentPrivate &other); + + ~QCLuceneDocumentPrivate(); + + Document *document; + bool deleteCLuceneDocument; + +private: + QCLuceneDocumentPrivate &operator=(const QCLuceneDocumentPrivate &other); +}; + +class QHELP_EXPORT QCLuceneDocument +{ +public: + QCLuceneDocument(); + ~QCLuceneDocument(); + + void add(QCLuceneField *field); + QCLuceneField* getField(const QString &name) const; + QString get(const QString &name) const; + QString toString() const; + void setBoost(qreal boost); + qreal getBoost() const; + void removeField(const QString &name); + void removeFields(const QString &name); + QStringList getValues(const QString &name) const; + void clear(); + +protected: + friend class QCLuceneHits; + friend class QCLuceneIndexReader; + friend class QCLuceneIndexWriter; + friend class QCLuceneIndexSearcher; + friend class QCLuceneMultiSearcher; + QSharedDataPointer<QCLuceneDocumentPrivate> d; + +private: + mutable QList<QCLuceneField*> fieldList; +}; + +QT_END_NAMESPACE + +#endif // QDOCUMENT_P_H diff --git a/tools/assistant/lib/fulltextsearch/qfield.cpp b/tools/assistant/lib/fulltextsearch/qfield.cpp new file mode 100644 index 0000000..0c64fa8 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qfield.cpp @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qfield_p.h" +#include "qreader_p.h" +#include "qclucene_global_p.h" + +#include <CLucene.h> +#include <CLucene/document/Field.h> + +QT_BEGIN_NAMESPACE + +QCLuceneFieldPrivate::QCLuceneFieldPrivate() + : QSharedData() +{ + field = 0; + deleteCLuceneField = true; +} + +QCLuceneFieldPrivate::QCLuceneFieldPrivate(const QCLuceneFieldPrivate &other) + : QSharedData() +{ + field = _CL_POINTER(other.field); +} + +QCLuceneFieldPrivate::~QCLuceneFieldPrivate() +{ + if (deleteCLuceneField) + _CLDECDELETE(field); +} + + +QCLuceneField::QCLuceneField() + : d(new QCLuceneFieldPrivate()) + , reader(0) +{ + // nothing todo +} + +QCLuceneField::QCLuceneField(const QString &name, const QString &value, int configs) + : d(new QCLuceneFieldPrivate()) + , reader(0) +{ + TCHAR* fieldName = QStringToTChar(name); + TCHAR* fieldValue = QStringToTChar(value); + + d->field = new lucene::document::Field(fieldName, fieldValue, configs); + + delete [] fieldName; + delete [] fieldValue; +} + +QCLuceneField::QCLuceneField(const QString &name, QCLuceneReader *reader, + int configs) + : d(new QCLuceneFieldPrivate()) + , reader(reader) +{ + TCHAR* fieldName = QStringToTChar(name); + + reader->d->deleteCLuceneReader = false; // clucene takes ownership + d->field = new lucene::document::Field(fieldName, reader->d->reader, configs); + + delete [] fieldName; +} + +QCLuceneField::~QCLuceneField() +{ + delete reader; +} + +QString QCLuceneField::name() const +{ + return TCharToQString(d->field->name()); +} + +QString QCLuceneField::stringValue() const +{ + return TCharToQString((const TCHAR*)d->field->stringValue()); +} + +QCLuceneReader* QCLuceneField::readerValue() const +{ + return reader; +} + +bool QCLuceneField::isStored() const +{ + return d->field->isStored(); +} + +bool QCLuceneField::isIndexed() const +{ + return d->field->isIndexed(); +} + +bool QCLuceneField::isTokenized() const +{ + return d->field->isTokenized(); +} + +bool QCLuceneField::isCompressed() const +{ + return d->field->isCompressed(); +} + +void QCLuceneField::setConfig(int termVector) +{ + d->field->setConfig(termVector); +} + +bool QCLuceneField::isTermVectorStored() const +{ + return d->field->isTermVectorStored(); +} + +bool QCLuceneField::isStoreOffsetWithTermVector() const +{ + return d->field->isStoreOffsetWithTermVector(); +} + +bool QCLuceneField::isStorePositionWithTermVector() const +{ + return d->field->isStorePositionWithTermVector(); +} + +qreal QCLuceneField::getBoost() const +{ + return qreal(d->field->getBoost()); +} + +void QCLuceneField::setBoost(qreal value) +{ + d->field->setBoost(qreal(value)); +} + +bool QCLuceneField::isBinary() const +{ + return d->field->isBinary(); +} + +bool QCLuceneField::getOmitNorms() const +{ + return d->field->getOmitNorms(); +} + +void QCLuceneField::setOmitNorms(bool omitNorms) +{ + d->field->setOmitNorms(omitNorms); +} + +QString QCLuceneField::toString() const +{ + return TCharToQString(d->field->toString()); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qfield_p.h b/tools/assistant/lib/fulltextsearch/qfield_p.h new file mode 100644 index 0000000..86b6440 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qfield_p.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QFIELD_P_H +#define QFIELD_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qclucene_global_p.h" + +#include <QtCore/QString> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(document) + class Field; +CL_NS_END +CL_NS_USE(document) + +QT_BEGIN_NAMESPACE + +class QCLuceneReader; +class QCLuceneDocument; + +class QHELP_EXPORT QCLuceneFieldPrivate : public QSharedData +{ +public: + QCLuceneFieldPrivate(); + QCLuceneFieldPrivate(const QCLuceneFieldPrivate &other); + + ~QCLuceneFieldPrivate(); + + Field *field; + bool deleteCLuceneField; + +private: + QCLuceneFieldPrivate &operator=(const QCLuceneFieldPrivate &other); +}; + +class QHELP_EXPORT QCLuceneField +{ +public: + enum Store { + STORE_YES = 1, + STORE_NO = 2, + STORE_COMPRESS = 4 + }; + + enum Index { + INDEX_NO = 16, + INDEX_TOKENIZED = 32, + INDEX_UNTOKENIZED = 64, + INDEX_NONORMS = 128 + }; + + enum TermVector { + TERMVECTOR_NO = 256, + TERMVECTOR_YES = 512, + TERMVECTOR_WITH_POSITIONS = 1024, + TERMVECTOR_WITH_OFFSETS = 2048 + }; + + QCLuceneField(const QString &name, const QString &value, int configs); + QCLuceneField(const QString &name, QCLuceneReader *reader, int configs); + ~QCLuceneField(); + + QString name() const; + QString stringValue() const; + QCLuceneReader* readerValue() const; + bool isStored() const; + bool isIndexed() const; + bool isTokenized() const; + bool isCompressed() const; + void setConfig(int termVector); + bool isTermVectorStored() const; + bool isStoreOffsetWithTermVector() const; + bool isStorePositionWithTermVector() const; + qreal getBoost() const; + void setBoost(qreal value); + bool isBinary() const; + bool getOmitNorms() const; + void setOmitNorms(bool omitNorms); + QString toString() const; + +protected: + QCLuceneField(); + friend class QCLuceneDocument; + QSharedDataPointer<QCLuceneFieldPrivate> d; + +private: + QCLuceneReader* reader; +}; + +QT_END_NAMESPACE + +#endif // QFIELD_P_H diff --git a/tools/assistant/lib/fulltextsearch/qfilter.cpp b/tools/assistant/lib/fulltextsearch/qfilter.cpp new file mode 100644 index 0000000..2437339 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qfilter.cpp @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qfilter_p.h" + +#include <CLucene.h> +#include <CLucene/search/Filter.h> + +QT_BEGIN_NAMESPACE + +QCLuceneFilterPrivate::QCLuceneFilterPrivate() + : QSharedData() +{ + filter = 0; + deleteCLuceneFilter = true; +} + +QCLuceneFilterPrivate::QCLuceneFilterPrivate(const QCLuceneFilterPrivate &other) + : QSharedData() +{ + filter = _CL_POINTER(other.filter); +} + +QCLuceneFilterPrivate::~QCLuceneFilterPrivate () +{ + if (deleteCLuceneFilter) + _CLDECDELETE(filter); +} + + +QCLuceneFilter::QCLuceneFilter() + : d(new QCLuceneFilterPrivate()) +{ + // nothing todo +} + +QCLuceneFilter::~QCLuceneFilter() +{ + // nothing todo +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qfilter_p.h b/tools/assistant/lib/fulltextsearch/qfilter_p.h new file mode 100644 index 0000000..fcc0674 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qfilter_p.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QFilter_P_H +#define QFilter_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qclucene_global_p.h" + +#include <QtCore/QSharedData> +#include <QtCore/QSharedDataPointer> + +CL_NS_DEF(search) + class Filter; +CL_NS_END +CL_NS_USE(search) + +QT_BEGIN_NAMESPACE + +class QCLuceneHits; +class QCLuceneSearcher; + +class QHELP_EXPORT QCLuceneFilterPrivate : public QSharedData +{ +public: + QCLuceneFilterPrivate(); + QCLuceneFilterPrivate(const QCLuceneFilterPrivate &other); + + ~QCLuceneFilterPrivate (); + + Filter *filter; + bool deleteCLuceneFilter; + +private: + QCLuceneFilterPrivate &operator=(const QCLuceneFilterPrivate &other); +}; + +class QHELP_EXPORT QCLuceneFilter +{ + QCLuceneFilter(); + virtual ~QCLuceneFilter(); + +protected: + friend class QCLuceneHits; + friend class QCLuceneSearcher; + QSharedDataPointer<QCLuceneFilterPrivate> d; +}; + +QT_END_NAMESPACE + +#endif // QFilter_P_H diff --git a/tools/assistant/lib/fulltextsearch/qhits.cpp b/tools/assistant/lib/fulltextsearch/qhits.cpp new file mode 100644 index 0000000..b3dbea7 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qhits.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qhits_p.h" +#include "qsearchable_p.h" + +#include <CLucene.h> +#include <CLucene/search/SearchHeader.h> + +QT_BEGIN_NAMESPACE + +QCLuceneHitsPrivate::QCLuceneHitsPrivate() + : QSharedData() +{ + hits = 0; + deleteCLuceneHits = true; +} + +QCLuceneHitsPrivate::QCLuceneHitsPrivate(const QCLuceneHitsPrivate &other) + : QSharedData() +{ + hits = _CL_POINTER(other.hits); +} + +QCLuceneHitsPrivate::~QCLuceneHitsPrivate() +{ + if (deleteCLuceneHits) + _CLDECDELETE(hits); +} + + +QCLuceneHits::QCLuceneHits(const QCLuceneSearcher &searcher, + const QCLuceneQuery &query, const QCLuceneFilter &filter) + : d(new QCLuceneHitsPrivate()) +{ + d->hits = new lucene::search::Hits(searcher.d->searchable, query.d->query, + filter.d->filter); +} + +QCLuceneHits::QCLuceneHits(const QCLuceneSearcher &searcher, const QCLuceneQuery &query, + const QCLuceneFilter &filter, const QCLuceneSort &sort) + : d(new QCLuceneHitsPrivate()) +{ + d->hits = new lucene::search::Hits(searcher.d->searchable, query.d->query, + filter.d->filter, sort.d->sort); +} + +QCLuceneHits::~QCLuceneHits() +{ + // nothing todo +} + +QCLuceneDocument QCLuceneHits::document(const qint32 index) +{ + // TODO: check this + QCLuceneDocument document; + document.d->deleteCLuceneDocument = false; + lucene::document::Document &doc = d->hits->doc(int32_t(index)); + document.d->document = &doc; + + return document; +} + +qint32 QCLuceneHits::length() const +{ + return qint32(d->hits->length()); +} + +qint32 QCLuceneHits::id(const qint32 index) +{ + return qint32(d->hits->id(int32_t(index))); +} + +qreal QCLuceneHits::score(const qint32 index) +{ + return qreal(d->hits->score(int32_t(index))); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qhits_p.h b/tools/assistant/lib/fulltextsearch/qhits_p.h new file mode 100644 index 0000000..fb6666b --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qhits_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QHITS_P_H +#define QHITS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qsort_p.h" +#include "qquery_p.h" +#include "qfilter_p.h" +#include "qdocument_p.h" +#include "qclucene_global_p.h" + +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(search) + class Hits; +CL_NS_END +CL_NS_USE(search) + +QT_BEGIN_NAMESPACE + +class QCLuceneSearcher; + +class QHELP_EXPORT QCLuceneHitsPrivate : public QSharedData +{ +public: + QCLuceneHitsPrivate(); + QCLuceneHitsPrivate(const QCLuceneHitsPrivate &other); + + ~QCLuceneHitsPrivate(); + + Hits *hits; + bool deleteCLuceneHits; + +private: + QCLuceneHitsPrivate &operator=(const QCLuceneHitsPrivate &other); +}; + +class QHELP_EXPORT QCLuceneHits +{ +public: + QCLuceneHits(const QCLuceneSearcher &searcher, const QCLuceneQuery &query, + const QCLuceneFilter &filter); + QCLuceneHits(const QCLuceneSearcher &searcher, const QCLuceneQuery &query, + const QCLuceneFilter &filter, const QCLuceneSort &sort); + virtual ~QCLuceneHits(); + + QCLuceneDocument document(const qint32 index); + qint32 length() const; + qint32 id (const qint32 index); + qreal score(const qint32 index); + +protected: + friend class QCLuceneSearcher; + QSharedDataPointer<QCLuceneHitsPrivate> d; +}; + +QT_END_NAMESPACE + +#endif // QHITS_P_H diff --git a/tools/assistant/lib/fulltextsearch/qindexreader.cpp b/tools/assistant/lib/fulltextsearch/qindexreader.cpp new file mode 100644 index 0000000..5f967cc --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qindexreader.cpp @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qindexreader_p.h" +#include "qclucene_global_p.h" + +#include <CLucene.h> +#include <CLucene/index/IndexReader.h> + +QT_BEGIN_NAMESPACE + +QCLuceneIndexReaderPrivate::QCLuceneIndexReaderPrivate() + : QSharedData() +{ + reader = 0; + deleteCLuceneIndexReader = true; +} + +QCLuceneIndexReaderPrivate::QCLuceneIndexReaderPrivate(const QCLuceneIndexReaderPrivate &other) + : QSharedData() +{ + reader = _CL_POINTER(other.reader); +} + +QCLuceneIndexReaderPrivate::~QCLuceneIndexReaderPrivate() +{ + if (deleteCLuceneIndexReader) + _CLDECDELETE(reader); +} + + +QCLuceneIndexReader::QCLuceneIndexReader() + : d(new QCLuceneIndexReaderPrivate()) +{ + // nothing todo, private +} + +QCLuceneIndexReader::~QCLuceneIndexReader() +{ + // nothing todo +} + +bool QCLuceneIndexReader::isLuceneFile(const QString &filename) +{ + using namespace lucene::index; + + return IndexReader::isLuceneFile(filename); +} + +bool QCLuceneIndexReader::indexExists(const QString &directory) +{ + using namespace lucene::index; + return IndexReader::indexExists(directory); +} + +QCLuceneIndexReader QCLuceneIndexReader::open(const QString &path) +{ + using namespace lucene::index; + + QCLuceneIndexReader indexReader; + indexReader.d->reader = IndexReader::open(path); + + return indexReader; +} + +void QCLuceneIndexReader::unlock(const QString &path) +{ + using namespace lucene::index; + IndexReader::unlock(path); +} + +bool QCLuceneIndexReader::isLocked(const QString &directory) +{ + using namespace lucene::index; + return IndexReader::isLocked(directory); +} + +quint64 QCLuceneIndexReader::lastModified(const QString &directory) +{ + using namespace lucene::index; + return quint64(IndexReader::lastModified(directory)); +} + +qint64 QCLuceneIndexReader::getCurrentVersion(const QString &directory) +{ + using namespace lucene::index; + return qint64(IndexReader::getCurrentVersion(directory)); +} + +void QCLuceneIndexReader::close() +{ + d->reader->close(); +} + +bool QCLuceneIndexReader::isCurrent() +{ + return d->reader->isCurrent(); +} + +void QCLuceneIndexReader::undeleteAll() +{ + d->reader->undeleteAll(); +} + +qint64 QCLuceneIndexReader::getVersion() +{ + return qint64(d->reader->getVersion()); +} + +void QCLuceneIndexReader::deleteDocument(qint32 docNum) +{ + d->reader->deleteDocument(int32_t(docNum)); +} + +bool QCLuceneIndexReader::hasNorms(const QString &field) +{ + TCHAR *fieldName = QStringToTChar(field); + bool retValue = d->reader->hasNorms(fieldName); + delete [] fieldName; + + return retValue; +} + +qint32 QCLuceneIndexReader::deleteDocuments(const QCLuceneTerm &term) +{ + return d->reader->deleteDocuments(term.d->term); +} + +bool QCLuceneIndexReader::document(qint32 index, QCLuceneDocument &document) +{ + if (!document.d->document) + document.d->document = new lucene::document::Document(); + + if (d->reader->document(int32_t(index), document.d->document)) + return true; + + return false; +} + +void QCLuceneIndexReader::setNorm(qint32 doc, const QString &field, qreal value) +{ + TCHAR *fieldName = QStringToTChar(field); + d->reader->setNorm(int32_t(doc), fieldName, qreal(value)); + delete [] fieldName; +} + +void QCLuceneIndexReader::setNorm(qint32 doc, const QString &field, quint8 value) +{ + TCHAR *fieldName = QStringToTChar(field); + d->reader->setNorm(int32_t(doc), fieldName, uint8_t(value)); + delete [] fieldName; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qindexreader_p.h b/tools/assistant/lib/fulltextsearch/qindexreader_p.h new file mode 100644 index 0000000..4a7330d --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qindexreader_p.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QINDEXREADER_P_H +#define QINDEXREADER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qterm_p.h" +#include "qdocument_p.h" +#include "qclucene_global_p.h" + +#include <QtCore/QList> +#include <QtCore/QString> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(index) + class IndexReader; +CL_NS_END +CL_NS_USE(index) + +QT_BEGIN_NAMESPACE + +class QCLuceneIndexWriter; +class QCLuceneIndexSearcher; + +class QHELP_EXPORT QCLuceneIndexReaderPrivate : public QSharedData +{ +public: + QCLuceneIndexReaderPrivate(); + QCLuceneIndexReaderPrivate(const QCLuceneIndexReaderPrivate &other); + + ~QCLuceneIndexReaderPrivate(); + + IndexReader *reader; + bool deleteCLuceneIndexReader; + +private: + QCLuceneIndexReaderPrivate &operator=(const QCLuceneIndexReaderPrivate &other); +}; + +class QHELP_EXPORT QCLuceneIndexReader +{ +public: + enum FieldOption { + ALL = 1, + INDEXED = 2, + UNINDEXED = 4, + INDEXED_WITH_TERMVECTOR = 8, + INDEXED_NO_TERMVECTOR = 16, + TERMVECTOR = 32, + TERMVECTOR_WITH_POSITION = 64, + TERMVECTOR_WITH_OFFSET = 128, + TERMVECTOR_WITH_POSITION_OFFSET = 256 + }; + + virtual ~QCLuceneIndexReader(); + + static bool isLuceneFile(const QString &filename); + static bool indexExists(const QString &directory); + static QCLuceneIndexReader open(const QString &path); + + static void unlock(const QString &path); + static bool isLocked(const QString &directory); + + static quint64 lastModified(const QString &directory); + static qint64 getCurrentVersion(const QString &directory); + + void close(); + bool isCurrent(); + void undeleteAll(); + qint64 getVersion(); + void deleteDocument(qint32 docNum); + bool hasNorms(const QString &field); + qint32 deleteDocuments(const QCLuceneTerm &term); + bool document(qint32 index, QCLuceneDocument &document); + void setNorm(qint32 doc, const QString &field, qreal value); + void setNorm(qint32 doc, const QString &field, quint8 value); + +protected: + friend class QCLuceneIndexWriter; + friend class QCLuceneIndexSearcher; + QSharedDataPointer<QCLuceneIndexReaderPrivate> d; + +private: + QCLuceneIndexReader(); +}; + +QT_END_NAMESPACE + +#endif // QINDEXREADER_P_H diff --git a/tools/assistant/lib/fulltextsearch/qindexwriter.cpp b/tools/assistant/lib/fulltextsearch/qindexwriter.cpp new file mode 100644 index 0000000..890cc67 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qindexwriter.cpp @@ -0,0 +1,183 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qindexwriter_p.h" +#include "qindexreader_p.h" + +#include <CLucene.h> +#include <CLucene/index/IndexWriter.h> + +QT_BEGIN_NAMESPACE + +QCLuceneIndexWriterPrivate::QCLuceneIndexWriterPrivate() + : QSharedData() +{ + writer = 0; + deleteCLuceneIndexWriter = true; +} + +QCLuceneIndexWriterPrivate::QCLuceneIndexWriterPrivate(const QCLuceneIndexWriterPrivate &other) + : QSharedData() +{ + writer = _CL_POINTER(other.writer); +} + +QCLuceneIndexWriterPrivate::~QCLuceneIndexWriterPrivate() +{ + if (deleteCLuceneIndexWriter) + _CLDECDELETE(writer); +} + + +QCLuceneIndexWriter::QCLuceneIndexWriter(const QString &path, + QCLuceneAnalyzer &analyzer, + bool create, bool closeDir) + : d(new QCLuceneIndexWriterPrivate()) + , analyzer(analyzer) +{ + d->writer = new lucene::index::IndexWriter(path, + analyzer.d->analyzer, create, closeDir); +} + +QCLuceneIndexWriter::~QCLuceneIndexWriter() +{ + // nothing todo +} + +void QCLuceneIndexWriter::close() +{ + d->writer->close(); +} + +void QCLuceneIndexWriter::optimize() +{ + d->writer->optimize(); +} + +qint32 QCLuceneIndexWriter::docCount() +{ + return qint32(d->writer->docCount()); +} + +QCLuceneAnalyzer QCLuceneIndexWriter::getAnalyzer() +{ + return analyzer; +} + +void QCLuceneIndexWriter::addIndexes(const QList<QCLuceneIndexReader*> &readers) +{ + using namespace lucene::index; + IndexReader** readerArray = new IndexReader*[readers.count()]; + + for (int i = 0; i < readers.count(); ++i) + readerArray[i] = (readers.at(i))->d->reader; + + d->writer->addIndexes(readerArray); + delete readerArray; +} + +void QCLuceneIndexWriter::addDocument(QCLuceneDocument &doc, + QCLuceneAnalyzer &analyzer) +{ + if (doc.d->document) + d->writer->addDocument(doc.d->document, analyzer.d->analyzer); +} + +qint32 QCLuceneIndexWriter::getMaxFieldLength() const +{ + return qint32(d->writer->getMaxFieldLength()); +} + +void QCLuceneIndexWriter::setMaxFieldLength(qint32 value) +{ + d->writer->setMaxFieldLength(int32_t(value)); +} + +qint32 QCLuceneIndexWriter::getMaxBufferedDocs() const +{ + return qint32(d->writer->getMaxBufferedDocs()); +} + +void QCLuceneIndexWriter::setMaxBufferedDocs(qint32 value) +{ + d->writer->setMaxBufferedDocs(int32_t(value)); +} + +qint64 QCLuceneIndexWriter::getWriteLockTimeout() const +{ + return qint64(d->writer->getWriteLockTimeout()); +} + +void QCLuceneIndexWriter::setWriteLockTimeout(qint64 writeLockTimeout) +{ + d->writer->setWriteLockTimeout(int64_t(writeLockTimeout)); +} + +qint64 QCLuceneIndexWriter::getCommitLockTimeout() const +{ + return qint64(d->writer->getCommitLockTimeout()); +} + +void QCLuceneIndexWriter::setCommitLockTimeout(qint64 commitLockTimeout) +{ + d->writer->setCommitLockTimeout(int64_t(commitLockTimeout)); +} + +qint32 QCLuceneIndexWriter::getMergeFactor() const +{ + return qint32(d->writer->getMergeFactor()); +} + +void QCLuceneIndexWriter::setMergeFactor(qint32 value) +{ + d->writer->setMergeFactor(int32_t(value)); +} + +qint32 QCLuceneIndexWriter::getTermIndexInterval() const +{ + return qint32(d->writer->getTermIndexInterval()); +} + +void QCLuceneIndexWriter::setTermIndexInterval(qint32 interval) +{ + d->writer->setTermIndexInterval(int32_t(interval)); +} + +qint32 QCLuceneIndexWriter::getMinMergeDocs() const +{ + return qint32(d->writer->getMinMergeDocs()); +} + +void QCLuceneIndexWriter::setMinMergeDocs(qint32 value) +{ + d->writer->setMinMergeDocs(int32_t(value)); +} + +qint32 QCLuceneIndexWriter::getMaxMergeDocs() const +{ + return qint32(d->writer->getMaxMergeDocs()); +} + +void QCLuceneIndexWriter::setMaxMergeDocs(qint32 value) +{ + d->writer->setMaxMergeDocs(int32_t(value)); +} + +bool QCLuceneIndexWriter::getUseCompoundFile() const +{ + return d->writer->getUseCompoundFile(); +} + +void QCLuceneIndexWriter::setUseCompoundFile(bool value) +{ + d->writer->setUseCompoundFile(value); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qindexwriter_p.h b/tools/assistant/lib/fulltextsearch/qindexwriter_p.h new file mode 100644 index 0000000..e793494 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qindexwriter_p.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QINDEXWRITER_P_H +#define QINDEXWRITER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qanalyzer_p.h" +#include "qdocument_p.h" +#include "qclucene_global_p.h" + +#include <QtCore/QString> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(index) + class IndexWriter; +CL_NS_END +CL_NS_USE(index) + +QT_BEGIN_NAMESPACE + +class QCLuceneIndexReader; + +class QHELP_EXPORT QCLuceneIndexWriterPrivate : public QSharedData +{ +public: + QCLuceneIndexWriterPrivate(); + QCLuceneIndexWriterPrivate(const QCLuceneIndexWriterPrivate &other); + + ~QCLuceneIndexWriterPrivate(); + + IndexWriter *writer; + bool deleteCLuceneIndexWriter; + +private: + QCLuceneIndexWriterPrivate &operator=(const QCLuceneIndexWriterPrivate &other); +}; + +class QHELP_EXPORT QCLuceneIndexWriter +{ +public: + enum { + DEFAULT_MERGE_FACTOR = 10, + COMMIT_LOCK_TIMEOUT = 10000, + DEFAULT_MAX_BUFFERED_DOCS = 10, + DEFAULT_MAX_FIELD_LENGTH = 10000, + DEFAULT_TERM_INDEX_INTERVAL = 128, + DEFAULT_MAX_MERGE_DOCS = 0x7FFFFFFFL + }; + + QCLuceneIndexWriter(const QString &path, QCLuceneAnalyzer &analyzer, + bool create, bool closeDir = true); + virtual ~QCLuceneIndexWriter(); + + void close(); + void optimize(); + qint32 docCount(); + QCLuceneAnalyzer getAnalyzer(); + + void addIndexes(const QList<QCLuceneIndexReader*> &readers); + void addDocument(QCLuceneDocument &doc, QCLuceneAnalyzer &analyzer); + + qint32 getMaxFieldLength() const; + void setMaxFieldLength(qint32 value); + + qint32 getMaxBufferedDocs() const; + void setMaxBufferedDocs(qint32 value); + + qint64 getWriteLockTimeout() const; + void setWriteLockTimeout(qint64 writeLockTimeout); + + qint64 getCommitLockTimeout() const; + void setCommitLockTimeout(qint64 commitLockTimeout); + + qint32 getMergeFactor() const; + void setMergeFactor(qint32 value); + + qint32 getTermIndexInterval() const; + void setTermIndexInterval(qint32 interval); + + qint32 getMinMergeDocs() const; + void setMinMergeDocs(qint32 value); + + qint32 getMaxMergeDocs() const; + void setMaxMergeDocs(qint32 value); + + bool getUseCompoundFile() const; + void setUseCompoundFile(bool value); + +protected: + QSharedDataPointer<QCLuceneIndexWriterPrivate> d; + +private: + QCLuceneAnalyzer analyzer; +}; + +QT_END_NAMESPACE + +#endif // QINDEXWRITER_P_H diff --git a/tools/assistant/lib/fulltextsearch/qquery.cpp b/tools/assistant/lib/fulltextsearch/qquery.cpp new file mode 100644 index 0000000..2210220 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qquery.cpp @@ -0,0 +1,350 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qquery_p.h" +#include "qclucene_global_p.h" + +#include <CLucene.h> +#include <CLucene/search/PhraseQuery.h> +#include <CLucene/search/SearchHeader.h> + +QT_BEGIN_NAMESPACE + +QCLuceneQueryPrivate::QCLuceneQueryPrivate() + : QSharedData() +{ + query = 0; + deleteCLuceneQuery = true; +} + +QCLuceneQueryPrivate::QCLuceneQueryPrivate(const QCLuceneQueryPrivate &other) + : QSharedData() +{ + query = _CL_POINTER(other.query); +} + +QCLuceneQueryPrivate::~QCLuceneQueryPrivate() +{ + if (deleteCLuceneQuery) + _CLDECDELETE(query); +} + + +QCLuceneQuery::QCLuceneQuery() + : d(new QCLuceneQueryPrivate()) +{ + // nothing todo, private +} + +QCLuceneQuery::~QCLuceneQuery() +{ + // nothing todo +} + +void QCLuceneQuery::setBoost(qreal boost) +{ + d->query->setBoost(qreal(boost)); +} + +qreal QCLuceneQuery::getBoost() const +{ + return qreal(d->query->getBoost()); +} + +QString QCLuceneQuery::getQueryName() const +{ + return TCharToQString(d->query->getQueryName()); +} + +bool QCLuceneQuery::instanceOf(const QString &other) const +{ + if (other == getQueryName()) + return true; + + return false; +} + +QString QCLuceneQuery::toString(const QString &field) const +{ + TCHAR *fieldName = QStringToTChar(field); + QString retValue = TCharToQString(d->query->toString(fieldName)); + delete [] fieldName; + + return retValue; +} + +quint32 QCLuceneQuery::hashCode() const +{ + return quint32(d->query->hashCode()); +} + +QString QCLuceneQuery::toString() const +{ + return TCharToQString(d->query->toString()); +} + +bool QCLuceneQuery::equals(const QCLuceneQuery &other) const +{ + return d->query->equals(other.d->query); +} + + +QCLucenePrefixQuery::QCLucenePrefixQuery(const QCLuceneTerm &prefix) + : QCLuceneQuery() + , prefix(prefix) +{ + d->query = new lucene::search::PrefixQuery(prefix.d->term); +} + +QCLucenePrefixQuery::~QCLucenePrefixQuery() +{ + // nothing todo +} + +QString QCLucenePrefixQuery::getClassName() +{ + return TCharToQString(lucene::search::PrefixQuery::getClassName()); +} + +QCLuceneTerm QCLucenePrefixQuery::getPrefix() const +{ + return prefix; +} + + +QCLuceneRangeQuery::QCLuceneRangeQuery(const QCLuceneTerm &lowerTerm, + const QCLuceneTerm &upperTerm, + bool inclusive) + : QCLuceneQuery() + , lowerTerm(lowerTerm) + , upperTerm(upperTerm) +{ + d->query = new lucene::search::RangeQuery(lowerTerm.d->term, + upperTerm.d->term, inclusive); +} + +QCLuceneRangeQuery::~QCLuceneRangeQuery() +{ + // nothing todo +} + +QString QCLuceneRangeQuery::getClassName() +{ + return TCharToQString(lucene::search::RangeQuery::getClassName()); +} + +QCLuceneTerm QCLuceneRangeQuery::getLowerTerm() const +{ + return lowerTerm; +} + +QCLuceneTerm QCLuceneRangeQuery::getUpperTerm() const +{ + return upperTerm; +} + +bool QCLuceneRangeQuery::isInclusive() const +{ + lucene::search::RangeQuery *query = + static_cast<lucene::search::RangeQuery*> (d->query); + + if (query == 0) + return false; + + return query->isInclusive(); +} + +QString QCLuceneRangeQuery::getField() const +{ + lucene::search::RangeQuery *query = + static_cast<lucene::search::RangeQuery*> (d->query); + + if (query == 0) + return QString(); + + return TCharToQString(query->getField()); +} + + +QCLuceneTermQuery::QCLuceneTermQuery(const QCLuceneTerm &term) + : QCLuceneQuery() + , term(term) +{ + d->query = new lucene::search::TermQuery(term.d->term); +} + +QCLuceneTermQuery::~QCLuceneTermQuery() +{ + // nothing todo +} + +QString QCLuceneTermQuery::getClassName() +{ + return TCharToQString(lucene::search::TermQuery::getClassName()); +} + +QCLuceneTerm QCLuceneTermQuery::getTerm() const +{ + return term; +} + + +QCLuceneBooleanQuery::QCLuceneBooleanQuery() + : QCLuceneQuery() +{ + d->query = new lucene::search::BooleanQuery(); +} + +QCLuceneBooleanQuery::~QCLuceneBooleanQuery() +{ + qDeleteAll(queries); +} + +QString QCLuceneBooleanQuery::getClassName() +{ + return TCharToQString(lucene::search::BooleanQuery::getClassName()); +} + +quint32 QCLuceneBooleanQuery::getClauseCount() const +{ + lucene::search::BooleanQuery *query = + static_cast<lucene::search::BooleanQuery*> (d->query); + + if (query == 0) + return 1024; + + return quint32(query->getClauseCount()); +} + +quint32 QCLuceneBooleanQuery::getMaxClauseCount() const +{ + lucene::search::BooleanQuery *query = + static_cast<lucene::search::BooleanQuery*> (d->query); + + if (query == 0) + return 1024; + + return quint32(query->getMaxClauseCount()); +} + +void QCLuceneBooleanQuery::setMaxClauseCount(quint32 maxClauseCount) +{ + lucene::search::BooleanQuery *query = + static_cast<lucene::search::BooleanQuery*> (d->query); + + if (query == 0) + return; + + query->setMaxClauseCount(size_t(maxClauseCount)); +} + +void QCLuceneBooleanQuery::add(QCLuceneQuery *query, bool required, bool prohibited) +{ + add(query, false, required, prohibited); +} + +void QCLuceneBooleanQuery::add(QCLuceneQuery *query, bool delQuery, + bool required, bool prohibited) +{ + lucene::search::BooleanQuery *booleanQuery = + static_cast<lucene::search::BooleanQuery*> (d->query); + + if (booleanQuery == 0) + return; + + booleanQuery->add(query->d->query, delQuery, required, prohibited); + + if (delQuery) { + queries.append(query); + query->d->deleteCLuceneQuery = false; + } +} + + +QCLucenePhraseQuery::QCLucenePhraseQuery() + : QCLuceneQuery() +{ + d->query = new lucene::search::PhraseQuery(); +} + +QCLucenePhraseQuery::~QCLucenePhraseQuery() +{ + termList.clear(); +} + +QString QCLucenePhraseQuery::getClassName() +{ + return TCharToQString(lucene::search::RangeQuery::getClassName()); +} + +qint32 QCLucenePhraseQuery::getSlop() const +{ + lucene::search::PhraseQuery *phraseQuery = + static_cast<lucene::search::PhraseQuery*> (d->query); + + if (phraseQuery == 0) + return 0; + + return qint32(phraseQuery->getSlop()); +} + +void QCLucenePhraseQuery::setSlop(const qint32 slop) +{ + lucene::search::PhraseQuery *phraseQuery = + static_cast<lucene::search::PhraseQuery*> (d->query); + + if (phraseQuery == 0) + return; + + phraseQuery->setSlop(int32_t(slop)); +} + +void QCLucenePhraseQuery::addTerm(const QCLuceneTerm &term) +{ + lucene::search::PhraseQuery *phraseQuery = + static_cast<lucene::search::PhraseQuery*> (d->query); + + if (phraseQuery == 0) + return; + + termList.append(term); + phraseQuery->add(term.d->term); +} + +void QCLucenePhraseQuery::addTerm(const QCLuceneTerm &term, qint32 position) +{ + lucene::search::PhraseQuery *phraseQuery = + static_cast<lucene::search::PhraseQuery*> (d->query); + + if (phraseQuery == 0) + return; + + termList.insert(position, term); + phraseQuery->add(term.d->term, int32_t(position)); + +} + +QString QCLucenePhraseQuery::getFieldName() const +{ + lucene::search::PhraseQuery *phraseQuery = + static_cast<lucene::search::PhraseQuery*> (d->query); + + if (phraseQuery == 0) + return QString(); + + return TCharToQString(phraseQuery->getFieldName()); +} + +QList<QCLuceneTerm> QCLucenePhraseQuery::getTerms() const +{ + return termList; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qquery_p.h b/tools/assistant/lib/fulltextsearch/qquery_p.h new file mode 100644 index 0000000..42eaf07 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qquery_p.h @@ -0,0 +1,181 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QQUERY_P_H +#define QQUERY_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qterm_p.h" +#include "qclucene_global_p.h" + +#include <QtCore/QList> +#include <QtCore/QString> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(search) + class Query; +CL_NS_END +CL_NS_USE(search) + +QT_BEGIN_NAMESPACE + +class QCLuceneHits; +class QCLuceneTermQuery; +class QCLuceneRangeQuery; +class QCLuceneQueryParser; +class QCLucenePrefixQuery; +class QCLuceneBooleanQuery; +class QCLucenePhraseQuery; + +class QHELP_EXPORT QCLuceneQueryPrivate : public QSharedData +{ +public: + QCLuceneQueryPrivate(); + QCLuceneQueryPrivate(const QCLuceneQueryPrivate &other); + + ~QCLuceneQueryPrivate(); + + Query *query; + bool deleteCLuceneQuery; + +private: + QCLuceneQueryPrivate &operator=(const QCLuceneQueryPrivate &other); +}; + +class QHELP_EXPORT QCLuceneQuery +{ +public: + virtual ~QCLuceneQuery(); + + void setBoost(qreal boost); + qreal getBoost() const; + QString getQueryName() const; + bool instanceOf(const QString &other) const; + QString toString(const QString &field) const; + quint32 hashCode() const; + QString toString() const; + bool equals(const QCLuceneQuery &other) const; + +protected: + friend class QCLuceneHits; + friend class QCLuceneTermQuery; + friend class QCLuceneRangeQuery; + friend class QCLucenePrefixQuery; + friend class QCLuceneQueryParser; + friend class QCLuceneBooleanQuery; + friend class QCLucenePhraseQuery; + QSharedDataPointer<QCLuceneQueryPrivate> d; + +private: + QCLuceneQuery(); +}; + +class QHELP_EXPORT QCLucenePrefixQuery : public QCLuceneQuery +{ +public: + QCLucenePrefixQuery(const QCLuceneTerm &prefix); + ~QCLucenePrefixQuery(); + + static QString getClassName(); + + QCLuceneTerm getPrefix() const; + +private: + QCLuceneTerm prefix; +}; + +class QHELP_EXPORT QCLuceneRangeQuery : public QCLuceneQuery +{ +public: + QCLuceneRangeQuery(const QCLuceneTerm &lowerTerm, + const QCLuceneTerm &upperTerm, bool inclusive); + ~QCLuceneRangeQuery(); + + static QString getClassName(); + + QCLuceneTerm getLowerTerm() const; + QCLuceneTerm getUpperTerm() const; + + bool isInclusive() const; + QString getField() const; + +private: + QCLuceneTerm lowerTerm; + QCLuceneTerm upperTerm; +}; + +class QHELP_EXPORT QCLuceneTermQuery : public QCLuceneQuery +{ +public: + QCLuceneTermQuery(const QCLuceneTerm &term); + ~QCLuceneTermQuery(); + + static QString getClassName(); + + QCLuceneTerm getTerm() const; + +private: + QCLuceneTerm term; +}; + +class QHELP_EXPORT QCLuceneBooleanQuery : public QCLuceneQuery +{ +public: + QCLuceneBooleanQuery(); + ~QCLuceneBooleanQuery(); + + static QString getClassName(); + + quint32 getClauseCount() const; + quint32 getMaxClauseCount() const; + void setMaxClauseCount(quint32 maxClauseCount); + + void add(QCLuceneQuery *query, bool required, bool prohibited); + void add(QCLuceneQuery *query, bool delQuery, bool required, bool prohibited); + +private: + QList<QCLuceneQuery*> queries; +}; + +class QHELP_EXPORT QCLucenePhraseQuery : public QCLuceneQuery +{ +public: + QCLucenePhraseQuery(); + ~QCLucenePhraseQuery(); + + static QString getClassName(); + + qint32 getSlop() const; + void setSlop(const qint32 slop); + + void addTerm(const QCLuceneTerm &term); + void addTerm(const QCLuceneTerm &term, qint32 position); + + QString getFieldName() const; + QList<QCLuceneTerm> getTerms() const; + +private: + QList<QCLuceneTerm> termList; +}; + +QT_END_NAMESPACE + +#endif // QQUERY_P_H diff --git a/tools/assistant/lib/fulltextsearch/qqueryparser.cpp b/tools/assistant/lib/fulltextsearch/qqueryparser.cpp new file mode 100644 index 0000000..ce1b512 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qqueryparser.cpp @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qqueryparser_p.h" +#include "qquery_p.h" +#include "qclucene_global_p.h" + +#include <CLucene.h> +#include <CLucene/queryParser/QueryParser.h> + +QT_BEGIN_NAMESPACE + +QCLuceneQueryParserPrivate::QCLuceneQueryParserPrivate() + : QSharedData() +{ + queryParser = 0; + deleteCLuceneQueryParser = true; +} + +QCLuceneQueryParserPrivate::QCLuceneQueryParserPrivate(const QCLuceneQueryParserPrivate &other) + : QSharedData() +{ + queryParser = _CL_POINTER(other.queryParser); +} + +QCLuceneQueryParserPrivate::~QCLuceneQueryParserPrivate() +{ + if (deleteCLuceneQueryParser) + _CLDECDELETE(queryParser); +} + + +QCLuceneQueryParser::QCLuceneQueryParser(const QString &field, + QCLuceneAnalyzer &analyzer) + : d(new QCLuceneQueryParserPrivate()) + , field(field) + , analyzer(analyzer) +{ + TCHAR *fieldName = QStringToTChar(field); + + d->queryParser = new lucene::queryParser::QueryParser(fieldName, + analyzer.d->analyzer); + + delete [] fieldName; +} + +QCLuceneQueryParser::~QCLuceneQueryParser() +{ + // nothing todo +} + +QCLuceneQuery* QCLuceneQueryParser::parse(const QString &query) +{ + TCHAR *string = QStringToTChar(query); + + QCLuceneQuery *retValue = 0; + lucene::search::Query* q = d->queryParser->parse(string); + if (q) { + retValue = new QCLuceneQuery(); + retValue->d->query = q; + } + + delete [] string; + return retValue; +} + +QCLuceneQuery* QCLuceneQueryParser::parse(QCLuceneReader &reader) +{ + QCLuceneQuery *retValue = 0; + lucene::search::Query* q = d->queryParser->parse(reader.d->reader); + if (q) { + retValue = new QCLuceneQuery(); + retValue->d->query = q; + } + + return retValue; +} + +QCLuceneQuery* QCLuceneQueryParser::parse(const QString &query, const QString &field, + QCLuceneAnalyzer &analyzer) +{ + QCLuceneQueryParser parser(field, analyzer); + return parser.parse(query); +} + +QCLuceneAnalyzer QCLuceneQueryParser::getAnalyzer() +{ + return analyzer; +} + +QString QCLuceneQueryParser::getField() +{ + return field; +} + + +QCLuceneMultiFieldQueryParser::QCLuceneMultiFieldQueryParser( + const QStringList &fieldList, QCLuceneAnalyzer &analyzer) + : QCLuceneQueryParser(QLatin1String(""), analyzer) +{ + Q_UNUSED(fieldList) +} + +QCLuceneMultiFieldQueryParser::~QCLuceneMultiFieldQueryParser() +{ + // nothing todo +} + +QCLuceneQuery* QCLuceneMultiFieldQueryParser::parse(const QString &query, + const QStringList &fieldList, + QCLuceneAnalyzer &analyzer) +{ + QCLuceneBooleanQuery *retValue = new QCLuceneBooleanQuery(); + foreach (const QString &field, fieldList) { + QCLuceneQuery *q = QCLuceneQueryParser::parse(query, field, analyzer); + if (!q) { + delete retValue; + retValue = 0; break; + } else { + retValue->add(q, true, false, false); + } + } + + return retValue; +} + +QCLuceneQuery* QCLuceneMultiFieldQueryParser::parse(const QString &query, + const QStringList &fieldList, + QList<FieldFlags> flags, + QCLuceneAnalyzer &analyzer) +{ + QCLuceneBooleanQuery *retValue = new QCLuceneBooleanQuery(); + qint32 i = 0; + foreach (const QString &field, fieldList) { + QCLuceneQuery *q = QCLuceneQueryParser::parse(query, field, analyzer); + if (q) { + qint32 flag = flags.at(i); + switch (flag) { + case QCLuceneMultiFieldQueryParser::REQUIRED_FIELD: { + retValue->add(q, true, true, false); + } break; + + case QCLuceneMultiFieldQueryParser::PROHIBITED_FIELD: { + retValue->add(q, true, false, true); + } break; + + default: { + retValue->add(q, true, false, false); + } break; + } + + ++i; + } else { + delete retValue; + retValue = 0; break; + } + } + return retValue; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qqueryparser_p.h b/tools/assistant/lib/fulltextsearch/qqueryparser_p.h new file mode 100644 index 0000000..976ee63 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qqueryparser_p.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QQUERYPARSER_P_H +#define QQUERYPARSER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qreader_p.h" +#include "qanalyzer_p.h" +#include "qclucene_global_p.h" + +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(queryParser) + class QueryParser; +CL_NS_END +CL_NS_USE(queryParser) + +QT_BEGIN_NAMESPACE + +class QCLuceneQuery; +class QCLuceneMultiFieldQueryParser; + +class QHELP_EXPORT QCLuceneQueryParserPrivate : public QSharedData +{ +public: + QCLuceneQueryParserPrivate(); + QCLuceneQueryParserPrivate(const QCLuceneQueryParserPrivate &other); + + ~QCLuceneQueryParserPrivate(); + + QueryParser *queryParser; + bool deleteCLuceneQueryParser; + +private: + QCLuceneQueryParserPrivate &operator=(const QCLuceneQueryParserPrivate &other); +}; + +class QHELP_EXPORT QCLuceneQueryParser +{ +public: + QCLuceneQueryParser(const QString &field, QCLuceneAnalyzer &analyzer); + virtual ~QCLuceneQueryParser(); + + QCLuceneQuery* parse(const QString &query); + QCLuceneQuery* parse(QCLuceneReader &reader); + static QCLuceneQuery* parse(const QString &query, const QString &field, + QCLuceneAnalyzer &analyzer); + QCLuceneAnalyzer getAnalyzer(); + QString getField(); + +protected: + friend class QCLuceneMultiFieldQueryParser; + QSharedDataPointer<QCLuceneQueryParserPrivate> d; + +private: + QString field; + QCLuceneAnalyzer analyzer; +}; + +class QHELP_EXPORT QCLuceneMultiFieldQueryParser : public QCLuceneQueryParser +{ +public: + enum FieldFlags { + NORMAL_FIELD = 0, + REQUIRED_FIELD = 1, + PROHIBITED_FIELD = 2 + }; + + QCLuceneMultiFieldQueryParser(const QStringList &fieldList, + QCLuceneAnalyzer &analyzer); + ~QCLuceneMultiFieldQueryParser(); + + static QCLuceneQuery *parse(const QString &query, const QStringList &fieldList, + QCLuceneAnalyzer &analyzer); + static QCLuceneQuery *parse(const QString &query, const QStringList &fieldList, + QList<FieldFlags> flags, QCLuceneAnalyzer &analyzer); +}; + +QT_END_NAMESPACE + +#endif // QQUERYPARSER_P_H diff --git a/tools/assistant/lib/fulltextsearch/qreader.cpp b/tools/assistant/lib/fulltextsearch/qreader.cpp new file mode 100644 index 0000000..792056d --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qreader.cpp @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qreader_p.h" +#include "qclucene_global_p.h" + +#include <CLucene.h> +#include <CLucene/util/Reader.h> + +QT_BEGIN_NAMESPACE + +QCLuceneReaderPrivate::QCLuceneReaderPrivate() + : QSharedData() +{ + reader = 0; + deleteCLuceneReader = true; +} + +QCLuceneReaderPrivate::QCLuceneReaderPrivate(const QCLuceneReaderPrivate &other) + : QSharedData() +{ + reader = _CL_POINTER(other.reader); +} + +QCLuceneReaderPrivate::~QCLuceneReaderPrivate() +{ + if (deleteCLuceneReader) + _CLDECDELETE(reader); +} + + +QCLuceneReader::QCLuceneReader() + : d(new QCLuceneReaderPrivate()) +{ + // nothing todo +} + +QCLuceneReader::~QCLuceneReader() +{ + // nothing todo +} + + +QCLuceneStringReader::QCLuceneStringReader(const QString &value) + : QCLuceneReader() + , string(QStringToTChar(value)) +{ + d->reader = new lucene::util::StringReader(string); +} + +QCLuceneStringReader::QCLuceneStringReader(const QString &value, qint32 length) + : QCLuceneReader() + , string(QStringToTChar(value)) +{ + d->reader = new lucene::util::StringReader(string, int32_t(length)); +} + +QCLuceneStringReader::QCLuceneStringReader(const QString &value, qint32 length, + bool copyData) + : QCLuceneReader() + , string(QStringToTChar(value)) +{ + d->reader = new lucene::util::StringReader(string, int32_t(length), copyData); +} + +QCLuceneStringReader::~QCLuceneStringReader() +{ + delete [] string; +} + + +QCLuceneFileReader::QCLuceneFileReader(const QString &path, const QString &encoding, + qint32 cacheLength, qint32 cacheBuffer) + : QCLuceneReader() +{ + const QByteArray tmpPath = path.toLocal8Bit(); + const QByteArray tmpEncoding = encoding.toAscii(); + d->reader = new lucene::util::FileReader(tmpPath.constData(), + tmpEncoding.constData(), int32_t(cacheLength), int32_t(cacheBuffer)); +} + +QCLuceneFileReader::~QCLuceneFileReader() +{ + // nothing todo +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qreader_p.h b/tools/assistant/lib/fulltextsearch/qreader_p.h new file mode 100644 index 0000000..77c8007 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qreader_p.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QREADER_P_H +#define QREADER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qclucene_global_p.h" + +#include <QtCore/QString> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(util) + class Reader; +CL_NS_END +CL_NS_USE(util) + +QT_BEGIN_NAMESPACE + +class QCLuceneField; +class QCLuceneAnalyzer; +class QCLuceneDocument; +class QCLuceneQueryParser; +class QCLuceneStandardTokenizer; + +class QHELP_EXPORT QCLuceneReaderPrivate : public QSharedData +{ +public: + QCLuceneReaderPrivate(); + QCLuceneReaderPrivate(const QCLuceneReaderPrivate &other); + + ~QCLuceneReaderPrivate(); + + Reader* reader; + bool deleteCLuceneReader; + +private: + QCLuceneReaderPrivate &operator=(const QCLuceneReaderPrivate &other); +}; + +class QHELP_EXPORT QCLuceneReader +{ +public: + QCLuceneReader(); + virtual ~QCLuceneReader(); + +protected: + friend class QCLuceneField; + friend class QCLuceneAnalyzer; + friend class QCLuceneDocument; + friend class QCLuceneQueryParser; + friend class QCLuceneStandardTokenizer; + QSharedDataPointer<QCLuceneReaderPrivate> d; +}; + +class QCLuceneStringReader : public QCLuceneReader +{ +public: + QCLuceneStringReader(const QString &value); + QCLuceneStringReader(const QString &value, qint32 length); + QCLuceneStringReader(const QString &value, qint32 length, bool copyData); + + ~QCLuceneStringReader(); + +private: + TCHAR *string; +}; + +class QHELP_EXPORT QCLuceneFileReader : public QCLuceneReader +{ +public: + QCLuceneFileReader(const QString &path, const QString &encoding, + qint32 cacheLength = 13, qint32 cacheBuffer = 14); + ~QCLuceneFileReader(); +}; + +QT_END_NAMESPACE + +#endif // QREADER_P_H diff --git a/tools/assistant/lib/fulltextsearch/qsearchable.cpp b/tools/assistant/lib/fulltextsearch/qsearchable.cpp new file mode 100644 index 0000000..2d76b02 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qsearchable.cpp @@ -0,0 +1,195 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qsearchable_p.h" + +#include <CLucene.h> +#include <CLucene/search/SearchHeader.h> + +QT_BEGIN_NAMESPACE + +QCLuceneSearchablePrivate::QCLuceneSearchablePrivate() + : QSharedData() +{ + searchable = 0; + deleteCLuceneSearchable = true; +} + +QCLuceneSearchablePrivate::QCLuceneSearchablePrivate(const QCLuceneSearchablePrivate &other) + : QSharedData() +{ + searchable = _CL_POINTER(other.searchable); +} + +QCLuceneSearchablePrivate::~QCLuceneSearchablePrivate() +{ + if (deleteCLuceneSearchable) + _CLDECDELETE(searchable); +} + + +QCLuceneSearchable::QCLuceneSearchable() + : d(new QCLuceneSearchablePrivate()) +{ + // nothing todo +} + +QCLuceneSearchable::~QCLuceneSearchable() +{ + // nothing todo +} + + +QCLuceneSearcher::QCLuceneSearcher() + : QCLuceneSearchable() +{ + // nothing todo +} + +QCLuceneSearcher::~QCLuceneSearcher() +{ + // nothing todo; +} + +QCLuceneHits QCLuceneSearcher::search(const QCLuceneQuery &query) +{ + return search(query, QCLuceneFilter()); +} + +QCLuceneHits QCLuceneSearcher::search(const QCLuceneQuery &query, + const QCLuceneFilter &filter) +{ + return QCLuceneHits(*this, query, filter); +} + +QCLuceneHits QCLuceneSearcher::search(const QCLuceneQuery &query, + const QCLuceneSort &sort) +{ + return QCLuceneHits(*this, query, QCLuceneFilter(), sort); +} + +QCLuceneHits QCLuceneSearcher::search(const QCLuceneQuery &query, + const QCLuceneFilter &filter, + const QCLuceneSort &sort) +{ + return QCLuceneHits(*this, query, filter, sort); +} + + +QCLuceneIndexSearcher::QCLuceneIndexSearcher(const QString &path) + : QCLuceneSearcher() +{ + lucene::search::IndexSearcher *searcher = + new lucene::search::IndexSearcher(path); + + reader.d->reader = searcher->getReader(); + reader.d->deleteCLuceneIndexReader = false; + + d->searchable = searcher; +} + +QCLuceneIndexSearcher::QCLuceneIndexSearcher(const QCLuceneIndexReader &reader) + : QCLuceneSearcher() + , reader(reader) +{ + d->searchable = new lucene::search::IndexSearcher(reader.d->reader); +} + +QCLuceneIndexSearcher::~QCLuceneIndexSearcher() +{ + // nothing todo +} + +void QCLuceneIndexSearcher::close() +{ + d->searchable->close(); +} + +qint32 QCLuceneIndexSearcher::maxDoc() const +{ + return qint32(d->searchable->maxDoc()); +} + +QCLuceneIndexReader QCLuceneIndexSearcher::getReader() +{ + return reader; +} + +bool QCLuceneIndexSearcher::doc(qint32 i, QCLuceneDocument &document) +{ + return d->searchable->doc(int32_t(i), document.d->document); +} + + +QCLuceneMultiSearcher::QCLuceneMultiSearcher(const QList<QCLuceneSearchable> searchables) +: QCLuceneSearcher() +{ + lucene::search::Searchable** list= + _CL_NEWARRAY(lucene::search::Searchable*, searchables.count()); + + d->searchable = new lucene::search::MultiSearcher(list); + + _CLDELETE_ARRAY(list); +} + +QCLuceneMultiSearcher::~QCLuceneMultiSearcher() +{ + // nothing todo +} + +void QCLuceneMultiSearcher::close() +{ + d->searchable->close(); +} + +qint32 QCLuceneMultiSearcher::maxDoc() const +{ + return qint32(d->searchable->maxDoc()); +} + +qint32 QCLuceneMultiSearcher::subDoc(qint32 index) const +{ + lucene::search::MultiSearcher *searcher = + static_cast<lucene::search::MultiSearcher*> (d->searchable); + + if (searcher == 0) + return 0; + + return qint32(searcher->subDoc(int32_t(index))); +} + +qint32 QCLuceneMultiSearcher::subSearcher(qint32 index) const +{ + lucene::search::MultiSearcher *searcher = + static_cast<lucene::search::MultiSearcher*> (d->searchable); + + if (searcher == 0) + return 0; + + return qint32(searcher->subSearcher(int32_t(index))); +} + +qint32 QCLuceneMultiSearcher::searcherIndex(qint32 index) const +{ + lucene::search::MultiSearcher *searcher = + static_cast<lucene::search::MultiSearcher*> (d->searchable); + + if (searcher == 0) + return 0; + + return qint32(searcher->searcherIndex(int32_t(index))); +} + +bool QCLuceneMultiSearcher::doc(qint32 i, QCLuceneDocument &document) +{ + return d->searchable->doc(int32_t(i), document.d->document); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qsearchable_p.h b/tools/assistant/lib/fulltextsearch/qsearchable_p.h new file mode 100644 index 0000000..8e4da44 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qsearchable_p.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QSEARCHABLE_P_H +#define QSEARCHABLE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhits_p.h" +#include "qsort_p.h" +#include "qquery_p.h" +#include "qfilter_p.h" +#include "qdocument_p.h" +#include "qindexreader_p.h" +#include "qclucene_global_p.h" + +#include <QtCore/QList> +#include <QtCore/QString> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(search) + class Searcher; +CL_NS_END +CL_NS_USE(search) + +QT_BEGIN_NAMESPACE + +class QCLuceneHits; +class QCLuceneSearcher; +class QCLuceneIndexSearcher; +class QCLuceneMultiSearcher; + +class QHELP_EXPORT QCLuceneSearchablePrivate : public QSharedData +{ +public: + QCLuceneSearchablePrivate(); + QCLuceneSearchablePrivate(const QCLuceneSearchablePrivate &other); + + ~QCLuceneSearchablePrivate(); + + Searcher *searchable; + bool deleteCLuceneSearchable; + +private: + QCLuceneSearchablePrivate &operator=(const QCLuceneSearchablePrivate &other); +}; + +class QHELP_EXPORT QCLuceneSearchable +{ +public: + virtual ~QCLuceneSearchable(); + +protected: + friend class QCLuceneSearcher; + friend class QCLuceneIndexSearcher; + friend class QCLuceneMultiSearcher; + QSharedDataPointer<QCLuceneSearchablePrivate> d; + +private: + QCLuceneSearchable(); +}; + +class QHELP_EXPORT QCLuceneSearcher : public QCLuceneSearchable +{ +public: + QCLuceneSearcher(); + virtual ~QCLuceneSearcher(); + + QCLuceneHits search(const QCLuceneQuery &query); + QCLuceneHits search(const QCLuceneQuery &query, const QCLuceneFilter &filter); + QCLuceneHits search(const QCLuceneQuery &query, const QCLuceneSort &sort); + QCLuceneHits search(const QCLuceneQuery &query, const QCLuceneFilter &filter, + const QCLuceneSort &sort); + +protected: + friend class QCLuceneHits; +}; + +class QHELP_EXPORT QCLuceneIndexSearcher : public QCLuceneSearcher +{ +public: + QCLuceneIndexSearcher(const QString &path); + QCLuceneIndexSearcher(const QCLuceneIndexReader &reader); + ~QCLuceneIndexSearcher(); + + void close(); + qint32 maxDoc() const; + QCLuceneIndexReader getReader(); + bool doc(qint32 i, QCLuceneDocument &document); + +private: + QCLuceneIndexReader reader; +}; + +class QHELP_EXPORT QCLuceneMultiSearcher : public QCLuceneSearcher +{ +public: + QCLuceneMultiSearcher(const QList<QCLuceneSearchable> searchables); + ~QCLuceneMultiSearcher(); + + void close(); + qint32 maxDoc() const; + qint32 subDoc(qint32 index) const; + qint32 subSearcher(qint32 index) const; + qint32 searcherIndex(qint32 index) const; + bool doc(qint32 i, QCLuceneDocument &document); +}; + +QT_END_NAMESPACE + +#endif // QSEARCHABLE_P_H diff --git a/tools/assistant/lib/fulltextsearch/qsort.cpp b/tools/assistant/lib/fulltextsearch/qsort.cpp new file mode 100644 index 0000000..06d7276 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qsort.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qsort_p.h" +#include "qclucene_global_p.h" + +#include <CLucene.h> +#include <CLucene/search/Sort.h> + +QT_BEGIN_NAMESPACE + +QCLuceneSortPrivate::QCLuceneSortPrivate() + : QSharedData() +{ + sort = 0; + deleteCLuceneSort = true; +} + +QCLuceneSortPrivate::QCLuceneSortPrivate (const QCLuceneSortPrivate &other) + : QSharedData() +{ + sort = _CL_POINTER(other.sort); +} + +QCLuceneSortPrivate::~QCLuceneSortPrivate() +{ + if (deleteCLuceneSort) + _CLDECDELETE(sort); +} + + +QCLuceneSort::QCLuceneSort() + : d(new QCLuceneSortPrivate()) +{ + d->sort = new lucene::search::Sort(); +} + +QCLuceneSort::QCLuceneSort(const QStringList &fieldNames) + : d(new QCLuceneSortPrivate()) +{ + d->sort = new lucene::search::Sort(); + setSort(fieldNames); +} + +QCLuceneSort::QCLuceneSort(const QString &field, bool reverse) + : d(new QCLuceneSortPrivate()) +{ + d->sort = new lucene::search::Sort(); + setSort(field, reverse); +} + +QCLuceneSort::~QCLuceneSort() +{ + // nothing todo +} + +QString QCLuceneSort::toString() const +{ + return TCharToQString(d->sort->toString()); +} + +void QCLuceneSort::setSort(const QStringList &fieldNames) +{ + TCHAR **nameArray = new TCHAR*[fieldNames.count()]; + for (int i = 0; i < fieldNames.count(); ++i) + nameArray[i] = QStringToTChar(fieldNames.at(i)); + + d->sort->setSort((const TCHAR**)nameArray); + + for (int i = 0; i < fieldNames.count(); ++i) + delete [] nameArray[i]; + delete nameArray; +} + +void QCLuceneSort::setSort(const QString &field, bool reverse) +{ + TCHAR *name = QStringToTChar(field); + d->sort->setSort(name, reverse); + delete [] name; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qsort_p.h b/tools/assistant/lib/fulltextsearch/qsort_p.h new file mode 100644 index 0000000..5ec2a06 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qsort_p.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QSORT_P_H +#define QSORT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qclucene_global_p.h" + +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(search) + class Sort; +CL_NS_END +CL_NS_USE(search) + +QT_BEGIN_NAMESPACE + +class QCLuceneHits; +class QCLuceneField; + +class QHELP_EXPORT QCLuceneSortPrivate : public QSharedData +{ +public: + QCLuceneSortPrivate(); + QCLuceneSortPrivate (const QCLuceneSortPrivate &other); + + ~QCLuceneSortPrivate(); + + Sort *sort; + bool deleteCLuceneSort; + +private: + QCLuceneSortPrivate &operator=(const QCLuceneSortPrivate &other); +}; + +class QHELP_EXPORT QCLuceneSort +{ +public: + QCLuceneSort(); + QCLuceneSort(const QStringList &fieldNames); + QCLuceneSort(const QString &field, bool reverse = false); + + virtual ~QCLuceneSort(); + + QString toString() const; + void setSort(const QStringList &fieldNames); + void setSort(const QString &field, bool reverse = false); + +protected: + friend class QCLuceneHits; + QSharedDataPointer<QCLuceneSortPrivate> d; +}; + +QT_END_NAMESPACE + +#endif // QSORT_P_H diff --git a/tools/assistant/lib/fulltextsearch/qterm.cpp b/tools/assistant/lib/fulltextsearch/qterm.cpp new file mode 100644 index 0000000..156586f --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qterm.cpp @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qterm_p.h" +#include "qclucene_global_p.h" + +#include <CLucene.h> +#include <CLucene/index/IndexReader.h> + +QT_BEGIN_NAMESPACE + +QCLuceneTermPrivate::QCLuceneTermPrivate() + : QSharedData() +{ + term = 0; + deleteCLuceneTerm = true; +} + +QCLuceneTermPrivate::QCLuceneTermPrivate(const QCLuceneTermPrivate &other) + : QSharedData() +{ + term = _CL_POINTER(other.term); +} + +QCLuceneTermPrivate::~QCLuceneTermPrivate() +{ + if (deleteCLuceneTerm) + _CLDECDELETE(term); +} + + +QCLuceneTerm::QCLuceneTerm() + : d(new QCLuceneTermPrivate()) +{ + d->term = new lucene::index::Term(); +} + +QCLuceneTerm::QCLuceneTerm(const QString &field, const QString &text) + : d(new QCLuceneTermPrivate()) +{ + TCHAR *fieldName = QStringToTChar(field); + TCHAR *termText = QStringToTChar(text); + + d->term = new lucene::index::Term(fieldName, termText); + + delete [] fieldName; + delete [] termText; +} + +QCLuceneTerm::QCLuceneTerm(const QCLuceneTerm &fieldTerm, const QString &text) + : d(new QCLuceneTermPrivate()) +{ + TCHAR *termText = QStringToTChar(text); + d->term = new lucene::index::Term(fieldTerm.d->term, termText); + delete [] termText; +} + +QCLuceneTerm::~QCLuceneTerm() +{ + // nothing todo +} + +QString QCLuceneTerm::field() const +{ + return TCharToQString(d->term->field()); +} + +QString QCLuceneTerm::text() const +{ + return TCharToQString(d->term->text()); +} + +void QCLuceneTerm::set(const QString &field, const QString &text) +{ + set(field, text, true); +} + +void QCLuceneTerm::set(const QCLuceneTerm &fieldTerm, const QString &text) +{ + set(fieldTerm.field(), text, false); +} + +void QCLuceneTerm::set(const QString &field, const QString &text, bool internField) +{ + TCHAR *fieldName = QStringToTChar(field); + TCHAR *termText = QStringToTChar(text); + + d->term->set(fieldName, termText, internField); + + delete [] fieldName; + delete [] termText; +} + +bool QCLuceneTerm::equals(const QCLuceneTerm &other) const +{ + return d->term->equals(other.d->term); +} + +qint32 QCLuceneTerm::compareTo(const QCLuceneTerm &other) const +{ + return quint32(d->term->compareTo(other.d->term)); +} + +QString QCLuceneTerm::toString() const +{ + return TCharToQString(d->term->toString()); +} + +quint32 QCLuceneTerm::hashCode() const +{ + return quint32(d->term->hashCode()); +} + +quint32 QCLuceneTerm::textLength() const +{ + return quint32(d->term->textLength()); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qterm_p.h b/tools/assistant/lib/fulltextsearch/qterm_p.h new file mode 100644 index 0000000..474c909 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qterm_p.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QTERM_P_H +#define QTERM_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qclucene_global_p.h" + +#include <QtCore/QSharedData> +#include <QtCore/QString> +#include <QtCore/QSharedDataPointer> + +CL_NS_DEF(index) + class Term; +CL_NS_END +CL_NS_USE(index) + +QT_BEGIN_NAMESPACE + +class QCLuceneTermQuery; +class QCLuceneRangeQuery; +class QCLucenePrefixQuery; +class QCLuceneIndexReader; +class QCLucenePhraseQuery; + +class QHELP_EXPORT QCLuceneTermPrivate : public QSharedData +{ +public: + QCLuceneTermPrivate(); + QCLuceneTermPrivate(const QCLuceneTermPrivate &other); + + ~QCLuceneTermPrivate(); + + Term *term; + bool deleteCLuceneTerm; + +private: + QCLuceneTermPrivate &operator=(const QCLuceneTermPrivate &other); +}; + +class QHELP_EXPORT QCLuceneTerm +{ +public: + QCLuceneTerm(); + QCLuceneTerm(const QString &field, const QString &text); + QCLuceneTerm(const QCLuceneTerm &fieldTerm, const QString &text); + + virtual ~QCLuceneTerm(); + + QString field() const; + QString text() const; + + void set(const QString &field, const QString &text); + void set(const QCLuceneTerm &fieldTerm, const QString &text); + void set(const QString &field, const QString &text, bool internField); + + bool equals(const QCLuceneTerm &other) const; + qint32 compareTo(const QCLuceneTerm &other) const; + + QString toString() const; + quint32 hashCode() const; + quint32 textLength() const; + +protected: + friend class QCLuceneTermQuery; + friend class QCLuceneRangeQuery; + friend class QCLucenePrefixQuery; + friend class QCLuceneIndexReader; + friend class QCLucenePhraseQuery; + QSharedDataPointer<QCLuceneTermPrivate> d; +}; + +QT_END_NAMESPACE + +#endif // QTERM_P_H diff --git a/tools/assistant/lib/fulltextsearch/qtoken.cpp b/tools/assistant/lib/fulltextsearch/qtoken.cpp new file mode 100644 index 0000000..fa5d62a --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qtoken.cpp @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qtoken_p.h" +#include "qclucene_global_p.h" + +#include <CLucene.h> +#include <CLucene/analysis/AnalysisHeader.h> + +QT_BEGIN_NAMESPACE + +QCLuceneTokenPrivate::QCLuceneTokenPrivate() + : QSharedData() +{ + token = 0; + deleteCLuceneToken = true; +} + +QCLuceneTokenPrivate::QCLuceneTokenPrivate(const QCLuceneTokenPrivate &other) + : QSharedData() +{ + token = _CL_POINTER(other.token); +} + +QCLuceneTokenPrivate::~QCLuceneTokenPrivate() +{ + if (deleteCLuceneToken) + _CLDECDELETE(token); +} + + +QCLuceneToken::QCLuceneToken() + : d(new QCLuceneTokenPrivate()) + , tokenText(0) + , tokenType(0) +{ + d->token = new lucene::analysis::Token(); +} + +QCLuceneToken::QCLuceneToken(const QString &text, qint32 startOffset, + qint32 endOffset, const QString &defaultTyp) + : d(new QCLuceneTokenPrivate()) + , tokenText(QStringToTChar(text)) + , tokenType(QStringToTChar(defaultTyp)) +{ + d->token = new lucene::analysis::Token(tokenText, int32_t(startOffset), + int32_t(endOffset), tokenType); +} + +QCLuceneToken::~QCLuceneToken() +{ + delete [] tokenText; + delete [] tokenType; +} + +quint32 QCLuceneToken::bufferLength() const +{ + return quint32(d->token->bufferLength()); +} + +void QCLuceneToken::growBuffer(quint32 size) +{ + d->token->growBuffer(size_t(size)); +} + +qint32 QCLuceneToken::positionIncrement() const +{ + return qint32(d->token->getPositionIncrement()); +} + +void QCLuceneToken::setPositionIncrement(qint32 positionIncrement) +{ + d->token->setPositionIncrement(int32_t(positionIncrement)); +} + +QString QCLuceneToken::termText() const +{ + return TCharToQString(d->token->termText()); +} + +void QCLuceneToken::setTermText(const QString &text) +{ + delete [] tokenText; + tokenText = QStringToTChar(text); + d->token->setText(tokenText); +} + +quint32 QCLuceneToken::termTextLength() const +{ + return quint32(d->token->termTextLength()); +} + +void QCLuceneToken::resetTermTextLength() const +{ + d->token->resetTermTextLen(); +} + +qint32 QCLuceneToken::startOffset() const +{ + return quint32(d->token->startOffset()); +} + +void QCLuceneToken::setStartOffset(qint32 value) +{ + d->token->setStartOffset(int32_t(value)); +} + +qint32 QCLuceneToken::endOffset() const +{ + return quint32(d->token->endOffset()); +} + +void QCLuceneToken::setEndOffset(qint32 value) +{ + d->token->setEndOffset(int32_t(value)); +} + +QString QCLuceneToken::type() const +{ + return TCharToQString(d->token->type()); +} + +void QCLuceneToken::setType(const QString &type) +{ + delete [] tokenType; + tokenType = QStringToTChar(type); + d->token->setType(tokenType); +} + +QString QCLuceneToken::toString() const +{ + return TCharToQString(d->token->toString()); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qtoken_p.h b/tools/assistant/lib/fulltextsearch/qtoken_p.h new file mode 100644 index 0000000..1802f99 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qtoken_p.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QTOKEN_P_H +#define QTOKEN_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qclucene_global_p.h" + +#include <QtCore/QString> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(analysis) + class Token; +CL_NS_END +CL_NS_USE(analysis) + +QT_BEGIN_NAMESPACE + +class QCLuceneTokenizer; +class QCLuceneTokenStream; +class QCLuceneStandardTokenizer; + +class QHELP_EXPORT QCLuceneTokenPrivate : public QSharedData +{ +public: + QCLuceneTokenPrivate(); + QCLuceneTokenPrivate(const QCLuceneTokenPrivate &other); + + ~QCLuceneTokenPrivate(); + + Token *token; + bool deleteCLuceneToken; + +private: + QCLuceneTokenPrivate &operator=(const QCLuceneTokenPrivate &other); +}; + +class QHELP_EXPORT QCLuceneToken +{ +public: + QCLuceneToken(); + QCLuceneToken(const QString &text, qint32 startOffset, + qint32 endOffset, const QString &defaultTyp = QLatin1String("word")); + + virtual ~QCLuceneToken(); + + void set(const QString &text, qint32 startOffset, + qint32 endOffset, const QString &defaultTyp = QLatin1String("word")); + + quint32 bufferLength() const; + void growBuffer(quint32 size); + + qint32 positionIncrement() const; + void setPositionIncrement(qint32 positionIncrement); + + QString termText() const; + void setTermText(const QString &text); + + quint32 termTextLength() const; + void resetTermTextLength() const; + + qint32 startOffset() const; + void setStartOffset(qint32 value); + + qint32 endOffset() const; + void setEndOffset(qint32 value); + + QString type() const; + void setType(const QString &type); + + QString toString() const; + +protected: + friend class QCLuceneTokenizer; + friend class QCLuceneTokenStream; + friend class QCLuceneStandardTokenizer; + QSharedDataPointer<QCLuceneTokenPrivate> d; + +private: + TCHAR *tokenText; + TCHAR *tokenType; +}; + +QT_END_NAMESPACE + +#endif // QTOKEN_P_H diff --git a/tools/assistant/lib/fulltextsearch/qtokenizer.cpp b/tools/assistant/lib/fulltextsearch/qtokenizer.cpp new file mode 100644 index 0000000..9a07387 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qtokenizer.cpp @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qtokenizer_p.h" +#include "qclucene_global_p.h" + +#include <CLucene.h> +#include <CLucene/analysis/AnalysisHeader.h> + +QT_BEGIN_NAMESPACE + +QCLuceneTokenizer::QCLuceneTokenizer() + : QCLuceneTokenStream() +{ + // nothing todo +} + +QCLuceneTokenizer::QCLuceneTokenizer(const QCLuceneReader &reader) + : QCLuceneTokenStream() + , reader(reader) +{ + // nothing todo +} + +QCLuceneTokenizer::~QCLuceneTokenizer() +{ + close(); +} + +void QCLuceneTokenizer::close() +{ + d->tokenStream->close(); +} + +bool QCLuceneTokenizer::next(QCLuceneToken &token) +{ + return d->tokenStream->next(token.d->token); +} + + +QCLuceneStandardTokenizer::QCLuceneStandardTokenizer(const QCLuceneReader &reader) + : QCLuceneTokenizer(reader) +{ + d->tokenStream = + new lucene::analysis::standard::StandardTokenizer(reader.d->reader); +} + +QCLuceneStandardTokenizer::~QCLuceneStandardTokenizer() +{ + // nothing todo +} + +bool QCLuceneStandardTokenizer::readApostrophe(const QString &string, + QCLuceneToken &token) +{ + lucene::analysis::standard::StandardTokenizer *stdTokenizer = + static_cast<lucene::analysis::standard::StandardTokenizer*> (d->tokenStream); + + if (stdTokenizer == 0) + return false; + + TCHAR* value = QStringToTChar(string); + lucene::util::StringBuffer buffer(value); + bool retValue = stdTokenizer->ReadApostrophe(&buffer, token.d->token); + delete [] value; + + return retValue; +} + +bool QCLuceneStandardTokenizer::readAt(const QString &string, QCLuceneToken &token) +{ + lucene::analysis::standard::StandardTokenizer *stdTokenizer = + static_cast<lucene::analysis::standard::StandardTokenizer*> (d->tokenStream); + + if (stdTokenizer == 0) + return false; + + TCHAR* value = QStringToTChar(string); + lucene::util::StringBuffer buffer(value); + bool retValue = stdTokenizer->ReadAt(&buffer, token.d->token); + delete [] value; + + return retValue; +} + +bool QCLuceneStandardTokenizer::readCompany(const QString &string, + QCLuceneToken &token) +{ + lucene::analysis::standard::StandardTokenizer *stdTokenizer = + static_cast<lucene::analysis::standard::StandardTokenizer*> (d->tokenStream); + + if (stdTokenizer == 0) + return false; + + TCHAR* value = QStringToTChar(string); + lucene::util::StringBuffer buffer(value); + bool retValue = stdTokenizer->ReadCompany(&buffer, token.d->token); + delete [] value; + + return retValue; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qtokenizer_p.h b/tools/assistant/lib/fulltextsearch/qtokenizer_p.h new file mode 100644 index 0000000..1e7916c --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qtokenizer_p.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QTOKENIZER_P_H +#define QTOKENIZER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qtoken_p.h" +#include "qreader_p.h" +#include "qtokenstream_p.h" +#include "qclucene_global_p.h" + +#include <QtCore/QChar> +#include <QtCore/QString> + +QT_BEGIN_NAMESPACE + +class QHELP_EXPORT QCLuceneTokenizer : public QCLuceneTokenStream +{ +public: + QCLuceneTokenizer(const QCLuceneReader &reader); + virtual ~QCLuceneTokenizer(); + + void close(); + bool next(QCLuceneToken &token); + +protected: + friend class QCLuceneStandardTokenizer; + +private: + QCLuceneTokenizer(); + QCLuceneReader reader; +}; + +class QHELP_EXPORT QCLuceneStandardTokenizer : public QCLuceneTokenizer +{ +public: + QCLuceneStandardTokenizer(const QCLuceneReader &reader); + ~QCLuceneStandardTokenizer(); + + bool readApostrophe(const QString &string, QCLuceneToken &token); + bool readAt(const QString &string, QCLuceneToken &token); + bool readCompany(const QString &string, QCLuceneToken &token); +}; + +class QCLuceneCharTokenizer : public QCLuceneTokenizer +{ + +}; + +class QCLuceneLetterTokenizer : public QCLuceneCharTokenizer +{ + +}; + +class QCLuceneLowerCaseTokenizer : public QCLuceneLetterTokenizer +{ + +}; + +class QCLuceneWhitespaceTokenizer : public QCLuceneCharTokenizer +{ + +}; + +class QCLuceneKeywordTokenizer : public QCLuceneTokenizer +{ + +}; + +QT_END_NAMESPACE + +#endif // QTOKENIZER_P_H diff --git a/tools/assistant/lib/fulltextsearch/qtokenstream.cpp b/tools/assistant/lib/fulltextsearch/qtokenstream.cpp new file mode 100644 index 0000000..957a0c2 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qtokenstream.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qtokenstream_p.h" + +#include <CLucene.h> +#include <CLucene/analysis/AnalysisHeader.h> + +QT_BEGIN_NAMESPACE + +QCLuceneTokenStreamPrivate::QCLuceneTokenStreamPrivate() + : QSharedData() +{ + tokenStream = 0; + deleteCLuceneTokenStream = true; +} + +QCLuceneTokenStreamPrivate::QCLuceneTokenStreamPrivate(const QCLuceneTokenStreamPrivate &other) + : QSharedData() +{ + tokenStream = _CL_POINTER(other.tokenStream); +} + +QCLuceneTokenStreamPrivate::~QCLuceneTokenStreamPrivate() +{ + if (deleteCLuceneTokenStream) + _CLDECDELETE(tokenStream); +} + + +QCLuceneTokenStream::QCLuceneTokenStream() + : d(new QCLuceneTokenStreamPrivate()) +{ + // nothing todo +} + +QCLuceneTokenStream::~QCLuceneTokenStream() +{ + // nothing todo +} + +void QCLuceneTokenStream::close() +{ + d->tokenStream->close(); +} + +bool QCLuceneTokenStream::next(QCLuceneToken &token) +{ + return d->tokenStream->next(token.d->token); +} + +QT_END_NAMESPACE
\ No newline at end of file diff --git a/tools/assistant/lib/fulltextsearch/qtokenstream_p.h b/tools/assistant/lib/fulltextsearch/qtokenstream_p.h new file mode 100644 index 0000000..ef6e715 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qtokenstream_p.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QTOKENSTREAM_P_H +#define QTOKENSTREAM_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qtoken_p.h" +#include "qclucene_global_p.h" + +#include <QtCore/QString> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(analysis) + class TokenStream; +CL_NS_END +CL_NS_USE(analysis) + +QT_BEGIN_NAMESPACE + +class QCLuceneAnalyzer; +class QCLuceneTokenizer; +class QCLuceneStopAnalyzer; +class QCLuceneSimpleAnalyzer; +class QCLuceneKeywordAnalyzer; +class QCLuceneStandardAnalyzer; +class QCLuceneWhitespaceAnalyzer; +class QCLucenePerFieldAnalyzerWrapper; + +class QHELP_EXPORT QCLuceneTokenStreamPrivate : public QSharedData +{ +public: + QCLuceneTokenStreamPrivate(); + QCLuceneTokenStreamPrivate(const QCLuceneTokenStreamPrivate &other); + + ~QCLuceneTokenStreamPrivate(); + + TokenStream *tokenStream; + bool deleteCLuceneTokenStream; + +private: + QCLuceneTokenStreamPrivate &operator=(const QCLuceneTokenStreamPrivate &other); +}; + +class QHELP_EXPORT QCLuceneTokenStream +{ +public: + virtual ~QCLuceneTokenStream(); + + void close(); + bool next(QCLuceneToken &token); + +protected: + friend class QCLuceneAnalyzer; + friend class QCLuceneTokenizer; + friend class QCLuceneStopAnalyzer; + friend class QCLuceneSimpleAnalyzer; + friend class QCLuceneKeywordAnalyzer; + friend class QCLuceneStandardAnalyzer; + friend class QCLuceneWhitespaceAnalyzer; + friend class QCLucenePerFieldAnalyzerWrapper; + QSharedDataPointer<QCLuceneTokenStreamPrivate> d; + +private: + QCLuceneTokenStream(); +}; + +QT_END_NAMESPACE + +#endif // QTOKENSTREAM_P_H diff --git a/tools/assistant/lib/helpsystem.qrc b/tools/assistant/lib/helpsystem.qrc new file mode 100644 index 0000000..10efc6d --- /dev/null +++ b/tools/assistant/lib/helpsystem.qrc @@ -0,0 +1,8 @@ +<RCC> + <qresource prefix="/trolltech/assistant" > + <file>images/1leftarrow.png</file> + <file>images/1rightarrow.png</file> + <file>images/3leftarrow.png</file> + <file>images/3rightarrow.png</file> + </qresource> +</RCC> diff --git a/tools/assistant/lib/images/1leftarrow.png b/tools/assistant/lib/images/1leftarrow.png Binary files differnew file mode 100644 index 0000000..bd1a5a2 --- /dev/null +++ b/tools/assistant/lib/images/1leftarrow.png diff --git a/tools/assistant/lib/images/1rightarrow.png b/tools/assistant/lib/images/1rightarrow.png Binary files differnew file mode 100644 index 0000000..0c0c44a --- /dev/null +++ b/tools/assistant/lib/images/1rightarrow.png diff --git a/tools/assistant/lib/images/3leftarrow.png b/tools/assistant/lib/images/3leftarrow.png Binary files differnew file mode 100644 index 0000000..8d38b0f --- /dev/null +++ b/tools/assistant/lib/images/3leftarrow.png diff --git a/tools/assistant/lib/images/3rightarrow.png b/tools/assistant/lib/images/3rightarrow.png Binary files differnew file mode 100644 index 0000000..c2faf50 --- /dev/null +++ b/tools/assistant/lib/images/3rightarrow.png diff --git a/tools/assistant/lib/lib.pro b/tools/assistant/lib/lib.pro new file mode 100644 index 0000000..bd9ed53 --- /dev/null +++ b/tools/assistant/lib/lib.pro @@ -0,0 +1,65 @@ +QT += sql xml network +TEMPLATE = lib +TARGET = QtHelp +DEFINES += QHELP_LIB QT_CLUCENE_SUPPORT +CONFIG += qt warn_on + +include(../../../src/qbase.pri) + +QMAKE_TARGET_PRODUCT = Help +QMAKE_TARGET_DESCRIPTION = Help application framework. +DEFINES -= QT_ASCII_CAST_WARNINGS + +qclucene = QtCLucene$${QT_LIBINFIX} +if(!debug_and_release|build_pass):CONFIG(debug, debug|release) { + mac:qclucene = $${qclucene}_debug + win32:qclucene = $${qclucene}d +} +linux-lsb-g++:LIBS += --lsb-shared-libs=$$qclucene +unix:QMAKE_PKGCONFIG_REQUIRES += QtNetwork QtSql QtXml +LIBS += -l$$qclucene +unix:QMAKE_PKGCONFIG_REQUIRES += QtNetwork QtSql QtXml + +RESOURCES += helpsystem.qrc + +SOURCES += qhelpenginecore.cpp \ + qhelpengine.cpp \ + qhelpdbreader.cpp \ + qhelpcontentwidget.cpp \ + qhelpindexwidget.cpp \ + qhelpgenerator.cpp \ + qhelpdatainterface.cpp \ + qhelpprojectdata.cpp \ + qhelpcollectionhandler.cpp \ + qhelpsearchengine.cpp \ + qhelpsearchquerywidget.cpp \ + qhelpsearchresultwidget.cpp \ + qhelpsearchindex_default.cpp \ + qhelpsearchindexwriter_default.cpp \ + qhelpsearchindexreader_default.cpp + +# access to clucene +SOURCES += qhelpsearchindexwriter_clucene.cpp \ + qhelpsearchindexreader_clucene.cpp + +HEADERS += qhelpenginecore.h \ + qhelpengine.h \ + qhelpengine_p.h \ + qhelp_global.h \ + qhelpdbreader_p.h \ + qhelpcontentwidget.h \ + qhelpindexwidget.h \ + qhelpgenerator_p.h \ + qhelpdatainterface_p.h \ + qhelpprojectdata_p.h \ + qhelpcollectionhandler_p.h \ + qhelpsearchengine.h \ + qhelpsearchquerywidget.h \ + qhelpsearchresultwidget.h \ + qhelpsearchindex_default_p.h \ + qhelpsearchindexwriter_default_p.h \ + qhelpsearchindexreader_default_p.h + +# access to clucene +HEADERS += qhelpsearchindexwriter_clucene_p.h \ + qhelpsearchindexreader_clucene_p.h diff --git a/tools/assistant/lib/qhelp_global.h b/tools/assistant/lib/qhelp_global.h new file mode 100644 index 0000000..5f09a08 --- /dev/null +++ b/tools/assistant/lib/qhelp_global.h @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELP_GLOBAL_H +#define QHELP_GLOBAL_H + +#include <QtCore/qglobal.h> +#include <QtCore/QString> +#include <QtCore/QObject> +#include <QtCore/QRegExp> +#include <QtCore/QMutexLocker> +#include <QtGui/QTextDocument> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Help) + +#if !defined(QT_SHARED) && !defined(QT_DLL) +# define QHELP_EXPORT +#elif defined(QHELP_LIB) +# define QHELP_EXPORT Q_DECL_EXPORT +#else +# define QHELP_EXPORT Q_DECL_IMPORT +#endif + +class QHelpGlobal { +public: + static QString uniquifyConnectionName(const QString &name, void *pointer) + { + static int counter = 0; + static QMutex mutex; + + QMutexLocker locker(&mutex); + if (++counter > 1000) + counter = 0; + + return QString::fromLatin1("%1-%2-%3") + .arg(name).arg(long(pointer)).arg(counter); + }; + + static QString documentTitle(const QString &content) + { + QString title = QObject::tr("Untitled"); + if (!content.isEmpty()) { + int start = content.indexOf(QLatin1String("<title>"), 0, Qt::CaseInsensitive) + 7; + int end = content.indexOf(QLatin1String("</title>"), 0, Qt::CaseInsensitive); + if ((end - start) > 0) { + title = content.mid(start, end - start); + if (Qt::mightBeRichText(title) || title.contains(QLatin1Char('&'))) { + QTextDocument doc; + doc.setHtml(title); + title = doc.toPlainText(); + } + } + } + return title; + }; + + static QString charsetFromData(const QByteArray &data) + { + QString content = QString::fromUtf8(data.constData(), data.size()); + int start = + content.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(); + if (r.indexIn(meta) != -1) + return r.cap(1); + start = content.indexOf(QLatin1String("<meta"), end, + Qt::CaseInsensitive); + } + } + return QLatin1String("utf-8"); + } +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QHELP_GLOBAL_H diff --git a/tools/assistant/lib/qhelpcollectionhandler.cpp b/tools/assistant/lib/qhelpcollectionhandler.cpp new file mode 100644 index 0000000..2356591 --- /dev/null +++ b/tools/assistant/lib/qhelpcollectionhandler.cpp @@ -0,0 +1,595 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpcollectionhandler_p.h" +#include "qhelp_global.h" +#include "qhelpdbreader_p.h" + +#include <QtCore/QFile> +#include <QtCore/QDir> +#include <QtCore/QFileInfo> +#include <QtCore/QDebug> + +#include <QtSql/QSqlError> +#include <QtSql/QSqlDriver> + +QT_BEGIN_NAMESPACE + +QHelpCollectionHandler::QHelpCollectionHandler(const QString &collectionFile, QObject *parent) + : QObject(parent) + , m_dbOpened(false) + , m_collectionFile(collectionFile) + , m_connectionName(QString()) +{ + QFileInfo fi(m_collectionFile); + if (!fi.isAbsolute()) + m_collectionFile = fi.absoluteFilePath(); + m_query.clear(); +} + +QHelpCollectionHandler::~QHelpCollectionHandler() +{ + m_query.clear(); + if (m_dbOpened) + QSqlDatabase::removeDatabase(m_connectionName); +} + +bool QHelpCollectionHandler::isDBOpened() +{ + if (m_dbOpened) + return true; + emit error(tr("The collection file is not set up yet!")); + return false; +} + +QString QHelpCollectionHandler::collectionFile() const +{ + return m_collectionFile; +} + +bool QHelpCollectionHandler::openCollectionFile() +{ + if (m_dbOpened) + return m_dbOpened; + + m_connectionName = QHelpGlobal::uniquifyConnectionName( + QLatin1String("QHelpCollectionHandler"), this); + bool openingOk = true; + { + QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), + m_connectionName); + if (db.driver() + && db.driver()->lastError().type() == QSqlError::ConnectionError) { + emit error(tr("Cannot load sqlite database driver!")); + return false; + } + + db.setDatabaseName(collectionFile()); + openingOk = db.open(); + if (openingOk) + m_query = QSqlQuery(db); + } + if (!openingOk) { + QSqlDatabase::removeDatabase(m_connectionName); + emit error(tr("Cannot open collection file: %1").arg(collectionFile())); + return false; + } + + m_query.exec(QLatin1String("SELECT COUNT(*) FROM sqlite_master WHERE TYPE=\'table\'" + "AND Name=\'NamespaceTable\'")); + m_query.next(); + if (m_query.value(0).toInt() < 1) { + if (!createTables(&m_query)) { + emit error(tr("Cannot create tables in file %1!").arg(collectionFile())); + return false; + } + } + + m_dbOpened = true; + return m_dbOpened; +} + +bool QHelpCollectionHandler::copyCollectionFile(const QString &fileName) +{ + if (!m_dbOpened) + return false; + + QFileInfo fi(fileName); + if (fi.exists()) { + emit error(tr("The specified collection file already exists!")); + return false; + } + + if (!fi.absoluteDir().exists() && !QDir().mkpath(fi.absolutePath())) { + emit error(tr("Cannot create directory: %1").arg(fi.absolutePath())); + return false; + } + + QString colFile = fi.absoluteFilePath(); + QString connectionName = QHelpGlobal::uniquifyConnectionName( + QLatin1String("QHelpCollectionHandlerCopy"), this); + QSqlQuery *copyQuery = 0; + bool openingOk = true; + { + QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), connectionName); + db.setDatabaseName(colFile); + openingOk = db.open(); + if (openingOk) + copyQuery = new QSqlQuery(db); + } + + if (!openingOk) { + emit error(tr("Cannot open collection file: %1").arg(colFile)); + return false; + } + + if (!createTables(copyQuery)) { + emit error(tr("Cannot copy collection file: %1").arg(colFile)); + return false; + } + + QString oldBaseDir = QFileInfo(collectionFile()).absolutePath(); + QString oldFilePath; + QFileInfo newColFi(colFile); + m_query.exec(QLatin1String("SELECT Name, FilePath FROM NamespaceTable")); + while (m_query.next()) { + copyQuery->prepare(QLatin1String("INSERT INTO NamespaceTable VALUES(NULL, ?, ?)")); + copyQuery->bindValue(0, m_query.value(0).toString()); + oldFilePath = m_query.value(1).toString(); + if (!QDir::isAbsolutePath(oldFilePath)) + oldFilePath = oldBaseDir + QDir::separator() + oldFilePath; + copyQuery->bindValue(1, newColFi.absoluteDir().relativeFilePath(oldFilePath)); + copyQuery->exec(); + } + + m_query.exec(QLatin1String("SELECT NamespaceId, Name FROM FolderTable")); + while (m_query.next()) { + copyQuery->prepare(QLatin1String("INSERT INTO FolderTable VALUES(NULL, ?, ?)")); + copyQuery->bindValue(0, m_query.value(0).toString()); + copyQuery->bindValue(1, m_query.value(1).toString()); + copyQuery->exec(); + } + + m_query.exec(QLatin1String("SELECT Name FROM FilterAttributeTable")); + while (m_query.next()) { + copyQuery->prepare(QLatin1String("INSERT INTO FilterAttributeTable VALUES(NULL, ?)")); + copyQuery->bindValue(0, m_query.value(0).toString()); + copyQuery->exec(); + } + + m_query.exec(QLatin1String("SELECT Name FROM FilterNameTable")); + while (m_query.next()) { + copyQuery->prepare(QLatin1String("INSERT INTO FilterNameTable VALUES(NULL, ?)")); + copyQuery->bindValue(0, m_query.value(0).toString()); + copyQuery->exec(); + } + + m_query.exec(QLatin1String("SELECT NameId, FilterAttributeId FROM FilterTable")); + while (m_query.next()) { + copyQuery->prepare(QLatin1String("INSERT INTO FilterTable VALUES(?, ?)")); + copyQuery->bindValue(0, m_query.value(0).toInt()); + copyQuery->bindValue(1, m_query.value(1).toInt()); + copyQuery->exec(); + } + + m_query.exec(QLatin1String("SELECT Key, Value FROM SettingsTable")); + while (m_query.next()) { + if (m_query.value(0).toString() == QLatin1String("CluceneSearchNamespaces")) + continue; + copyQuery->prepare(QLatin1String("INSERT INTO SettingsTable VALUES(?, ?)")); + copyQuery->bindValue(0, m_query.value(0).toString()); + copyQuery->bindValue(1, m_query.value(1)); + copyQuery->exec(); + } + + copyQuery->clear(); + delete copyQuery; + QSqlDatabase::removeDatabase(connectionName); + return true; +} + +bool QHelpCollectionHandler::createTables(QSqlQuery *query) +{ + QStringList tables; + tables << QLatin1String("CREATE TABLE NamespaceTable (" + "Id INTEGER PRIMARY KEY, " + "Name TEXT, " + "FilePath TEXT )") + << QLatin1String("CREATE TABLE FolderTable (" + "Id INTEGER PRIMARY KEY, " + "NamespaceId INTEGER, " + "Name TEXT )") + << QLatin1String("CREATE TABLE FilterAttributeTable (" + "Id INTEGER PRIMARY KEY, " + "Name TEXT )") + << QLatin1String("CREATE TABLE FilterNameTable (" + "Id INTEGER PRIMARY KEY, " + "Name TEXT )") + << QLatin1String("CREATE TABLE FilterTable (" + "NameId INTEGER, " + "FilterAttributeId INTEGER )") + << QLatin1String("CREATE TABLE SettingsTable (" + "Key TEXT PRIMARY KEY, " + "Value BLOB )"); + + foreach (QString q, tables) { + if (!query->exec(q)) + return false; + } + return true; +} + +QStringList QHelpCollectionHandler::customFilters() const +{ + QStringList list; + if (m_dbOpened) { + m_query.exec(QLatin1String("SELECT Name FROM FilterNameTable")); + while (m_query.next()) + list.append(m_query.value(0).toString()); + } + return list; +} + +bool QHelpCollectionHandler::removeCustomFilter(const QString &filterName) +{ + if (!isDBOpened() || filterName.isEmpty()) + return false; + + int filterNameId = -1; + m_query.prepare(QLatin1String("SELECT Id FROM FilterNameTable WHERE Name=?")); + m_query.bindValue(0, filterName); + m_query.exec(); + if (m_query.next()) + filterNameId = m_query.value(0).toInt(); + + if (filterNameId < 0) { + emit error(tr("Unknown filter!")); + return false; + } + + m_query.prepare(QLatin1String("DELETE FROM FilterTable WHERE NameId=?")); + m_query.bindValue(0, filterNameId); + m_query.exec(); + + m_query.prepare(QLatin1String("DELETE FROM FilterNameTable WHERE Id=?")); + m_query.bindValue(0, filterNameId); + m_query.exec(); + + return true; +} + +bool QHelpCollectionHandler::addCustomFilter(const QString &filterName, + const QStringList &attributes) +{ + if (!isDBOpened() || filterName.isEmpty()) + return false; + + int nameId = -1; + m_query.prepare(QLatin1String("SELECT Id FROM FilterNameTable WHERE Name=?")); + m_query.bindValue(0, filterName); + m_query.exec(); + while (m_query.next()) { + nameId = m_query.value(0).toInt(); + break; + } + + m_query.exec(QLatin1String("SELECT Id, Name FROM FilterAttributeTable")); + QStringList idsToInsert = attributes; + QMap<QString, int> attributeMap; + while (m_query.next()) { + attributeMap.insert(m_query.value(1).toString(), + m_query.value(0).toInt()); + if (idsToInsert.contains(m_query.value(1).toString())) + idsToInsert.removeAll(m_query.value(1).toString()); + } + + foreach (QString id, idsToInsert) { + m_query.prepare(QLatin1String("INSERT INTO FilterAttributeTable VALUES(NULL, ?)")); + m_query.bindValue(0, id); + m_query.exec(); + attributeMap.insert(id, m_query.lastInsertId().toInt()); + } + + if (nameId < 0) { + m_query.prepare(QLatin1String("INSERT INTO FilterNameTable VALUES(NULL, ?)")); + m_query.bindValue(0, filterName); + if (m_query.exec()) + nameId = m_query.lastInsertId().toInt(); + } + + if (nameId < 0) { + emit error(tr("Cannot register filter %1!").arg(filterName)); + return false; + } + + m_query.prepare(QLatin1String("DELETE FROM FilterTable WHERE NameId=?")); + m_query.bindValue(0, nameId); + m_query.exec(); + + foreach (QString att, attributes) { + m_query.prepare(QLatin1String("INSERT INTO FilterTable VALUES(?, ?)")); + m_query.bindValue(0, nameId); + m_query.bindValue(1, attributeMap[att]); + if (!m_query.exec()) + return false; + } + return true; +} + +QHelpCollectionHandler::DocInfoList QHelpCollectionHandler::registeredDocumentations() const +{ + DocInfoList list; + if (m_dbOpened) { + m_query.exec(QLatin1String("SELECT a.Name, a.FilePath, b.Name " + "FROM NamespaceTable a, FolderTable b WHERE a.Id=b.NamespaceId")); + + while (m_query.next()) { + DocInfo info; + info.fileName = m_query.value(1).toString(); + info.folderName = m_query.value(2).toString(); + info.namespaceName = m_query.value(0).toString(); + list.append(info); + } + } + return list; +} + +bool QHelpCollectionHandler::registerDocumentation(const QString &fileName) +{ + if (!isDBOpened()) + return false; + + QHelpDBReader reader(fileName, QHelpGlobal::uniquifyConnectionName( + QLatin1String("QHelpCollectionHandler"), this), 0); + if (!reader.init()) { + emit error(tr("Cannot open documentation file %1!").arg(fileName)); + return false; + } + + QString ns = reader.namespaceName(); + if (ns.isEmpty()) { + emit error(tr("Invalid documentation file!")); + return false; + } + + int nsId = registerNamespace(ns, fileName); + if (nsId < 1) + return false; + + if (!registerVirtualFolder(reader.virtualFolder(), nsId)) + return false; + + addFilterAttributes(reader.filterAttributes()); + foreach (QString filterName, reader.customFilters()) + addCustomFilter(filterName, reader.filterAttributes(filterName)); + + optimizeDatabase(fileName); + + return true; +} + +bool QHelpCollectionHandler::unregisterDocumentation(const QString &namespaceName) +{ + if (!isDBOpened()) + return false; + + m_query.prepare(QLatin1String("SELECT Id FROM NamespaceTable WHERE Name=?")); + m_query.bindValue(0, namespaceName); + m_query.exec(); + + int nsId = -1; + if (m_query.next()) + nsId = m_query.value(0).toInt(); + + if (nsId < 0) { + emit error(tr("The namespace %1 was not registered!").arg(namespaceName)); + return false; + } + + m_query.prepare(QLatin1String("DELETE FROM NamespaceTable WHERE Id=?")); + m_query.bindValue(0, nsId); + m_query.exec(); + + m_query.prepare(QLatin1String("DELETE FROM FolderTable WHERE NamespaceId=?")); + m_query.bindValue(0, nsId); + return m_query.exec(); +} + +bool QHelpCollectionHandler::removeCustomValue(const QString &key) +{ + if (!isDBOpened()) + return false; + + m_query.prepare(QLatin1String("DELETE FROM SettingsTable WHERE Key=?")); + m_query.bindValue(0, key); + return m_query.exec(); +} + +QVariant QHelpCollectionHandler::customValue(const QString &key, + const QVariant &defaultValue) const +{ + QVariant value = defaultValue; + if (m_dbOpened) { + m_query.prepare(QLatin1String("SELECT COUNT(Key) FROM SettingsTable WHERE Key=?")); + m_query.bindValue(0, key); + if (!m_query.exec() || !m_query.next() || !m_query.value(0).toInt()) { + m_query.clear(); + return defaultValue; + } + + m_query.clear(); + m_query.prepare(QLatin1String("SELECT Value FROM SettingsTable WHERE Key=?")); + m_query.bindValue(0, key); + if (m_query.exec() && m_query.next()) + value = m_query.value(0); + m_query.clear(); + } + return value; +} + +bool QHelpCollectionHandler::setCustomValue(const QString &key, + const QVariant &value) +{ + if (!isDBOpened()) + return false; + + m_query.prepare(QLatin1String("SELECT Value FROM SettingsTable WHERE Key=?")); + m_query.bindValue(0, key); + m_query.exec(); + if (m_query.next()) { + m_query.prepare(QLatin1String("UPDATE SettingsTable SET Value=? where Key=?")); + m_query.bindValue(0, value); + m_query.bindValue(1, key); + } + else { + m_query.prepare(QLatin1String("INSERT INTO SettingsTable VALUES(?, ?)")); + m_query.bindValue(0, key); + m_query.bindValue(1, value); + } + return m_query.exec(); +} + +bool QHelpCollectionHandler::addFilterAttributes(const QStringList &attributes) +{ + if (!isDBOpened()) + return false; + + m_query.exec(QLatin1String("SELECT Name FROM FilterAttributeTable")); + QSet<QString> atts; + while (m_query.next()) + atts.insert(m_query.value(0).toString()); + + foreach (QString s, attributes) { + if (!atts.contains(s)) { + m_query.prepare(QLatin1String("INSERT INTO FilterAttributeTable VALUES(NULL, ?)")); + m_query.bindValue(0, s); + m_query.exec(); + } + } + return true; +} + +QStringList QHelpCollectionHandler::filterAttributes() const +{ + QStringList list; + if (m_dbOpened) { + m_query.exec(QLatin1String("SELECT Name FROM FilterAttributeTable")); + while (m_query.next()) + list.append(m_query.value(0).toString()); + } + return list; +} + +QStringList QHelpCollectionHandler::filterAttributes(const QString &filterName) const +{ + QStringList list; + if (m_dbOpened) { + m_query.prepare(QLatin1String("SELECT a.Name FROM FilterAttributeTable a, " + "FilterTable b, FilterNameTable c WHERE a.Id=b.FilterAttributeId " + "AND b.NameId=c.Id AND c.Name=?")); + m_query.bindValue(0, filterName); + m_query.exec(); + while (m_query.next()) + list.append(m_query.value(0).toString()); + } + return list; +} + +int QHelpCollectionHandler::registerNamespace(const QString &nspace, const QString &fileName) +{ + m_query.prepare(QLatin1String("SELECT COUNT(Id) FROM NamespaceTable WHERE Name=?")); + m_query.bindValue(0, nspace); + m_query.exec(); + while (m_query.next()) { + if (m_query.value(0).toInt() > 0) { + emit error(tr("Namespace %1 already exists!").arg(nspace)); + return -1; + } + } + + QFileInfo fi(m_collectionFile); + m_query.prepare(QLatin1String("INSERT INTO NamespaceTable VALUES(NULL, ?, ?)")); + m_query.bindValue(0, nspace); + m_query.bindValue(1, fi.absoluteDir().relativeFilePath(fileName)); + int namespaceId = -1; + if (m_query.exec()) + namespaceId = m_query.lastInsertId().toInt(); + if (namespaceId < 1) { + emit error(tr("Cannot register namespace!")); + return -1; + } + return namespaceId; +} + +bool QHelpCollectionHandler::registerVirtualFolder(const QString &folderName, int namespaceId) +{ + m_query.prepare(QLatin1String("INSERT INTO FolderTable VALUES(NULL, ?, ?)")); + m_query.bindValue(0, namespaceId); + m_query.bindValue(1, folderName); + return m_query.exec(); +} + +void QHelpCollectionHandler::optimizeDatabase(const QString &fileName) +{ + if (!QFile::exists(fileName)) + return; + + { // according to removeDatabase() documentation + QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), QLatin1String("optimize")); + db.setDatabaseName(fileName); + if (!db.open()) { + QSqlDatabase::removeDatabase(QLatin1String("optimize")); + emit error(tr("Cannot open database to optimize!")); + return; + } + + QSqlQuery query(db); + 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)")); + + db.close(); + } + + QSqlDatabase::removeDatabase(QLatin1String("optimize")); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpcollectionhandler_p.h b/tools/assistant/lib/qhelpcollectionhandler_p.h new file mode 100644 index 0000000..2520694 --- /dev/null +++ b/tools/assistant/lib/qhelpcollectionhandler_p.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPCOLLECTIONHANDLER_H +#define QHELPCOLLECTIONHANDLER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QList> +#include <QtCore/QString> +#include <QtCore/QObject> +#include <QtCore/QVariant> +#include <QtCore/QStringList> + +#include <QtSql/QSqlQuery> + +QT_BEGIN_NAMESPACE + +class QHelpCollectionHandler : public QObject +{ + Q_OBJECT + +public: + struct DocInfo + { + QString fileName; + QString folderName; + QString namespaceName; + }; + typedef QList<DocInfo> DocInfoList; + + QHelpCollectionHandler(const QString &collectionFile, QObject *parent = 0); + ~QHelpCollectionHandler(); + + QString collectionFile() const; + + bool openCollectionFile(); + bool copyCollectionFile(const QString &fileName); + + QStringList customFilters() const; + bool removeCustomFilter(const QString &filterName); + bool addCustomFilter(const QString &filterName, + const QStringList &attributes); + + DocInfoList registeredDocumentations() const; + bool registerDocumentation(const QString &fileName); + bool unregisterDocumentation(const QString &namespaceName); + + bool removeCustomValue(const QString &key); + QVariant customValue(const QString &key, const QVariant &defaultValue) const; + bool setCustomValue(const QString &key, const QVariant &value); + + bool addFilterAttributes(const QStringList &attributes); + QStringList filterAttributes() const; + QStringList filterAttributes(const QString &filterName) const; + + int registerNamespace(const QString &nspace, const QString &fileName); + bool registerVirtualFolder(const QString &folderName, int namespaceId); + void optimizeDatabase(const QString &fileName); + +signals: + void error(const QString &msg); + +private: + bool isDBOpened(); + bool createTables(QSqlQuery *query); + + bool m_dbOpened; + QString m_collectionFile; + QString m_connectionName; + mutable QSqlQuery m_query; +}; + +QT_END_NAMESPACE + +#endif //QHELPCOLLECTIONHANDLER_H diff --git a/tools/assistant/lib/qhelpcontentwidget.cpp b/tools/assistant/lib/qhelpcontentwidget.cpp new file mode 100644 index 0000000..c70aef3 --- /dev/null +++ b/tools/assistant/lib/qhelpcontentwidget.cpp @@ -0,0 +1,585 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpcontentwidget.h" +#include "qhelpenginecore.h" +#include "qhelpengine_p.h" +#include "qhelpdbreader_p.h" + +#include <QtCore/QDir> +#include <QtCore/QStack> +#include <QtCore/QThread> +#include <QtCore/QMutex> +#include <QtGui/QHeaderView> + +QT_BEGIN_NAMESPACE + +class QHelpContentItemPrivate +{ +public: + QHelpContentItemPrivate(const QString &t, const QString &l, + QHelpDBReader *r, QHelpContentItem *p) + { + parent = p; + title = t; + link = l; + helpDBReader = r; + } + + QList<QHelpContentItem*> childItems; + QHelpContentItem *parent; + QString title; + QString link; + QHelpDBReader *helpDBReader; +}; + +class QHelpContentProvider : public QThread +{ +public: + QHelpContentProvider(QHelpEnginePrivate *helpEngine); + ~QHelpContentProvider(); + void collectContents(const QString &customFilterName); + void stopCollecting(); + QHelpContentItem *rootItem(); + int nextChildCount() const; + +private: + void run(); + + QHelpEnginePrivate *m_helpEngine; + QHelpContentItem *m_rootItem; + QStringList m_filterAttributes; + QQueue<QHelpContentItem*> m_rootItems; + QMutex m_mutex; + bool m_abort; +}; + +class QHelpContentModelPrivate +{ +public: + QHelpContentItem *rootItem; + QHelpContentProvider *qhelpContentProvider; +}; + + + +/*! + \class QHelpContentItem + \inmodule QtHelp + \brief The QHelpContentItem class provides an item for use with QHelpContentModel. + \since 4.4 +*/ + +QHelpContentItem::QHelpContentItem(const QString &name, const QString &link, + QHelpDBReader *reader, QHelpContentItem *parent) +{ + d = new QHelpContentItemPrivate(name, link, reader, parent); +} + +/*! + Destroys the help content item. +*/ +QHelpContentItem::~QHelpContentItem() +{ + qDeleteAll(d->childItems); + delete d; +} + +void QHelpContentItem::appendChild(QHelpContentItem *item) +{ + d->childItems.append(item); +} + +/*! + Returns the child of the content item in the give \a row. + + \sa parent() +*/ +QHelpContentItem *QHelpContentItem::child(int row) const +{ + if (row >= childCount()) + return 0; + return d->childItems.value(row); +} + +/*! + Returns the number of child items. +*/ +int QHelpContentItem::childCount() const +{ + return d->childItems.count(); +} + +/*! + Returns the row of this item from its parents view. +*/ +int QHelpContentItem::row() const +{ + if (d->parent) + return d->parent->d->childItems.indexOf(const_cast<QHelpContentItem*>(this)); + return 0; +} + +/*! + Returns the title of the content item. +*/ +QString QHelpContentItem::title() const +{ + return d->title; +} + +/*! + Returns the URL of this content item. +*/ +QUrl QHelpContentItem::url() const +{ + return d->helpDBReader->urlOfPath(d->link); +} + +/*! + Returns the parent content item. +*/ +QHelpContentItem *QHelpContentItem::parent() const +{ + return d->parent; +} + +/*! + Returns the position of a given \a child. +*/ +int QHelpContentItem::childPosition(QHelpContentItem *child) const +{ + return d->childItems.indexOf(child); +} + + + +QHelpContentProvider::QHelpContentProvider(QHelpEnginePrivate *helpEngine) + : QThread(helpEngine) +{ + m_helpEngine = helpEngine; + m_rootItem = 0; + m_abort = false; +} + +QHelpContentProvider::~QHelpContentProvider() +{ + stopCollecting(); +} + +void QHelpContentProvider::collectContents(const QString &customFilterName) +{ + m_mutex.lock(); + m_filterAttributes = m_helpEngine->q->filterAttributes(customFilterName); + m_mutex.unlock(); + if (!isRunning()) { + start(LowPriority); + } else { + stopCollecting(); + start(LowPriority); + } +} + +void QHelpContentProvider::stopCollecting() +{ + if (!isRunning()) + return; + m_mutex.lock(); + m_abort = true; + m_mutex.unlock(); + wait(); +} + +QHelpContentItem *QHelpContentProvider::rootItem() +{ + QMutexLocker locker(&m_mutex); + return m_rootItems.dequeue(); +} + +int QHelpContentProvider::nextChildCount() const +{ + return m_rootItems.head()->childCount(); +} + +void QHelpContentProvider::run() +{ + QString title; + QString link; + int depth = 0; + QHelpContentItem *item = 0; + + m_mutex.lock(); + m_rootItem = new QHelpContentItem(QString(), QString(), 0); + m_rootItems.enqueue(m_rootItem); + QStringList atts = m_filterAttributes; + const QStringList fileNames = m_helpEngine->orderedFileNameList; + m_mutex.unlock(); + + foreach (QString dbFileName, fileNames) { + m_mutex.lock(); + if (m_abort) { + m_abort = false; + m_mutex.unlock(); + break; + } + m_mutex.unlock(); + QHelpDBReader reader(dbFileName, + QHelpGlobal::uniquifyConnectionName(dbFileName + + QLatin1String("FromQHelpContentProvider"), + QThread::currentThread()), 0); + if (!reader.init()) + continue; + foreach (const QByteArray& ba, reader.contentsForFilter(atts)) { + if (ba.size() < 1) + continue; + + int _depth = 0; + bool _root = false; + QStack<QHelpContentItem*> stack; + + QDataStream s(ba); + for (;;) { + s >> depth; + s >> link; + s >> title; + if (title.isEmpty()) + break; +CHECK_DEPTH: + if (depth == 0) { + m_mutex.lock(); + item = new QHelpContentItem(title, link, + m_helpEngine->fileNameReaderMap.value(dbFileName), m_rootItem); + m_rootItem->appendChild(item); + m_mutex.unlock(); + stack.push(item); + _depth = 1; + _root = true; + } else { + if (depth > _depth && _root) { + _depth = depth; + stack.push(item); + } + if (depth == _depth) { + item = new QHelpContentItem(title, link, + m_helpEngine->fileNameReaderMap.value(dbFileName), stack.top()); + stack.top()->appendChild(item); + } else if (depth < _depth) { + stack.pop(); + --_depth; + goto CHECK_DEPTH; + } + } + } + } + } + m_mutex.lock(); + m_abort = false; + m_mutex.unlock(); +} + + + +/*! + \class QHelpContentModel + \inmodule QtHelp + \brief The QHelpContentModel class provides a model that supplies content to views. + \since 4.4 +*/ + +/*! + \fn void QHelpContentModel::contentsCreationStarted() + + This signal is emitted when the creation of the contents has + started. The current contents are invalid from this point on + until the signal contentsCreated() is emitted. + + \sa isCreatingContents() +*/ + +/*! + \fn void QHelpContentModel::contentsCreated() + + This signal is emitted when the contents have been created. +*/ + +QHelpContentModel::QHelpContentModel(QHelpEnginePrivate *helpEngine) + : QAbstractItemModel(helpEngine) +{ + d = new QHelpContentModelPrivate(); + d->rootItem = 0; + d->qhelpContentProvider = new QHelpContentProvider(helpEngine); + + connect(d->qhelpContentProvider, SIGNAL(finished()), + this, SLOT(insertContents()), Qt::QueuedConnection); + connect(helpEngine->q, SIGNAL(setupStarted()), this, SLOT(invalidateContents())); +} + +/*! + Destroys the help content model. +*/ +QHelpContentModel::~QHelpContentModel() +{ + delete d->rootItem; + delete d; +} + +void QHelpContentModel::invalidateContents(bool onShutDown) +{ + if (onShutDown) + disconnect(this, SLOT(insertContents())); + d->qhelpContentProvider->stopCollecting(); + if (d->rootItem) { + delete d->rootItem; + d->rootItem = 0; + } + reset(); +} + +/*! + Creates new contents by querying the help system + for contents specified for the \a customFilterName. +*/ +void QHelpContentModel::createContents(const QString &customFilterName) +{ + d->qhelpContentProvider->collectContents(customFilterName); + emit contentsCreationStarted(); +} + +void QHelpContentModel::insertContents() +{ + int count; + if (d->rootItem) { + count = d->rootItem->childCount() - 1; + beginRemoveRows(QModelIndex(), 0, count > 0 ? count : 0); + delete d->rootItem; + d->rootItem = 0; + endRemoveRows(); + } + + count = d->qhelpContentProvider->nextChildCount() - 1; + beginInsertRows(QModelIndex(), 0, count > 0 ? count : 0); + d->rootItem = d->qhelpContentProvider->rootItem(); + endInsertRows(); + reset(); + emit contentsCreated(); +} + +/*! + Returns true if the contents are currently rebuilt, otherwise + false. +*/ +bool QHelpContentModel::isCreatingContents() const +{ + return d->qhelpContentProvider->isRunning(); +} + +/*! + Returns the help content item at the model index position + \a index. +*/ +QHelpContentItem *QHelpContentModel::contentItemAt(const QModelIndex &index) const +{ + if (index.isValid()) + return static_cast<QHelpContentItem*>(index.internalPointer()); + else + return d->rootItem; +} + +/*! + Returns the index of the item in the model specified by + the given \a row, \a column and \a parent index. +*/ +QModelIndex QHelpContentModel::index(int row, int column, const QModelIndex &parent) const +{ + if (!d->rootItem) + return QModelIndex(); + + QHelpContentItem *parentItem = contentItemAt(parent); + QHelpContentItem *item = parentItem->child(row); + if (!item) + return QModelIndex(); + return createIndex(row, column, item); +} + +/*! + Returns the parent of the model item with the given + \a index, or QModelIndex() if it has no parent. +*/ +QModelIndex QHelpContentModel::parent(const QModelIndex &index) const +{ + QHelpContentItem *item = contentItemAt(index); + if (!item) + return QModelIndex(); + + QHelpContentItem *parentItem = static_cast<QHelpContentItem*>(item->parent()); + if (!parentItem) + return QModelIndex(); + + QHelpContentItem *grandparentItem = static_cast<QHelpContentItem*>(parentItem->parent()); + if (!grandparentItem) + return QModelIndex(); + + int row = grandparentItem->childPosition(parentItem); + return createIndex(row, index.column(), parentItem); +} + +/*! + Returns the number of rows under the given \a parent. +*/ +int QHelpContentModel::rowCount(const QModelIndex &parent) const +{ + QHelpContentItem *parentItem = contentItemAt(parent); + if (!parentItem) + return 0; + return parentItem->childCount(); +} + +/*! + Returns the number of columns under the given \a parent. Currently returns always 1. +*/ +int QHelpContentModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + + return 1; +} + +/*! + Returns the data stored under the given \a role for + the item referred to by the \a index. +*/ +QVariant QHelpContentModel::data(const QModelIndex &index, int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + QHelpContentItem *item = contentItemAt(index); + if (!item) + return QVariant(); + return item->title(); +} + + + +/*! + \class QHelpContentWidget + \inmodule QtHelp + \brief The QHelpContentWidget class provides a tree view for displaying help content model items. + \since 4.4 +*/ + +/*! + \fn void QHelpContentWidget::linkActivated(const QUrl &link) + + This signal is emitted when a content item is activated and + its associated \a link should be shown. +*/ + +QHelpContentWidget::QHelpContentWidget() + : QTreeView(0) +{ + header()->hide(); + setUniformRowHeights(true); + connect(this, SIGNAL(activated(const QModelIndex&)), + this, SLOT(showLink(const QModelIndex&))); +} + +/*! + Returns the index of the content item with the \a link. + An invalid index is returned if no such an item exists. +*/ +QModelIndex QHelpContentWidget::indexOf(const QUrl &link) +{ + QHelpContentModel *contentModel = + qobject_cast<QHelpContentModel*>(model()); + if (!contentModel || link.scheme() != QLatin1String("qthelp")) + return QModelIndex(); + + m_syncIndex = QModelIndex(); + for (int i=0; i<contentModel->rowCount(); ++i) { + QHelpContentItem *itm = + contentModel->contentItemAt(contentModel->index(i, 0)); + if (itm && itm->url().host() == link.host()) { + QString path = link.path(); + if (path.startsWith(QLatin1Char('/'))) + path = path.mid(1); + if (searchContentItem(contentModel, contentModel->index(i, 0), path)) { + return m_syncIndex; + } + } + } + return QModelIndex(); +} + +bool QHelpContentWidget::searchContentItem(QHelpContentModel *model, + const QModelIndex &parent, const QString &path) +{ + QHelpContentItem *parentItem = model->contentItemAt(parent); + if (!parentItem) + return false; + + if (QDir::cleanPath(parentItem->url().path()) == path) { + m_syncIndex = parent; + return true; + } + + for (int i=0; i<parentItem->childCount(); ++i) { + if (searchContentItem(model, model->index(i, 0, parent), path)) + return true; + } + return false; +} + +void QHelpContentWidget::showLink(const QModelIndex &index) +{ + QHelpContentModel *contentModel = qobject_cast<QHelpContentModel*>(model()); + if (!contentModel) + return; + + QHelpContentItem *item = contentModel->contentItemAt(index); + if (!item) + return; + QUrl url = item->url(); + if (url.isValid()) + emit linkActivated(url); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpcontentwidget.h b/tools/assistant/lib/qhelpcontentwidget.h new file mode 100644 index 0000000..ceab7fe --- /dev/null +++ b/tools/assistant/lib/qhelpcontentwidget.h @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPCONTENTWIDGET_H +#define QHELPCONTENTWIDGET_H + +#include <QtHelp/qhelp_global.h> + +#include <QtCore/QQueue> +#include <QtCore/QString> +#include <QtGui/QTreeView> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Help) + +class QHelpEnginePrivate; +class QHelpDBReader; +class QHelpContentItemPrivate; +class QHelpContentModelPrivate; +class QHelpEngine; +class QHelpContentProvider; + +class QHELP_EXPORT QHelpContentItem +{ +public: + ~QHelpContentItem(); + + QHelpContentItem *child(int row) const; + int childCount() const; + QString title() const; + QUrl url() const; + int row() const; + QHelpContentItem *parent() const; + int childPosition(QHelpContentItem *child) const; + +private: + QHelpContentItem(const QString &name, const QString &link, + QHelpDBReader *reader, QHelpContentItem *parent = 0); + void appendChild(QHelpContentItem *child); + + QHelpContentItemPrivate *d; + friend class QHelpContentProvider; +}; + +class QHELP_EXPORT QHelpContentModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + ~QHelpContentModel(); + + void createContents(const QString &customFilterName); + QHelpContentItem *contentItemAt(const QModelIndex &index) const; + + QVariant data(const QModelIndex &index, int role) const; + QModelIndex index(int row, int column, + const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &index) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + bool isCreatingContents() const; + +Q_SIGNALS: + void contentsCreationStarted(); + void contentsCreated(); + +private Q_SLOTS: + void insertContents(); + void invalidateContents(bool onShutDown = false); + +private: + QHelpContentModel(QHelpEnginePrivate *helpEngine); + QHelpContentModelPrivate *d; + friend class QHelpEnginePrivate; +}; + +class QHELP_EXPORT QHelpContentWidget : public QTreeView +{ + Q_OBJECT + +public: + QModelIndex indexOf(const QUrl &link); + +Q_SIGNALS: + void linkActivated(const QUrl &link); + +private Q_SLOTS: + void showLink(const QModelIndex &index); + +private: + bool searchContentItem(QHelpContentModel *model, + const QModelIndex &parent, const QString &path); + QModelIndex m_syncIndex; + +private: + QHelpContentWidget(); + friend class QHelpEngine; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif + diff --git a/tools/assistant/lib/qhelpdatainterface.cpp b/tools/assistant/lib/qhelpdatainterface.cpp new file mode 100644 index 0000000..001c059 --- /dev/null +++ b/tools/assistant/lib/qhelpdatainterface.cpp @@ -0,0 +1,273 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpdatainterface_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \internal + \class QHelpDataContentItem + \since 4.4 + \brief The QHelpDataContentItem class provides an item which represents + a topic or section of the contents. + + Every item holds several pieces of information, most notably the title + which can later be displayed in a contents overview. The reference is used + to store a relative file link to the corresponding section in the + documentation. +*/ + +/*! + Constructs a new content item with \a parent as parent item. + The constucted item has the title \a title and links to the + location specified by \a reference. +*/ +QHelpDataContentItem::QHelpDataContentItem(QHelpDataContentItem *parent, + const QString &title, const QString &reference) + : m_title(title), m_reference(reference) +{ + if (parent) + parent->m_children.append(this); +} + +/*! + Destructs the item and its children. +*/ +QHelpDataContentItem::~QHelpDataContentItem() +{ + qDeleteAll(m_children); +} + +/*! + Returns the title of the item. +*/ +QString QHelpDataContentItem::title() const +{ + return m_title; +} + +/*! + Returns the file reference of the item. +*/ +QString QHelpDataContentItem::reference() const +{ + return m_reference; +} + +/*! + Returns a list of all its child items. +*/ +QList<QHelpDataContentItem*> QHelpDataContentItem::children() const +{ + return m_children; +} + +bool QHelpDataIndexItem::operator==(const QHelpDataIndexItem & other) const +{ + return (other.name == name) + && (other.reference == reference); +} + + + +/*! + \internal + \class QHelpDataFilterSection + \since 4.4 +*/ + +/*! + Constructs a help data filter section. +*/ +QHelpDataFilterSection::QHelpDataFilterSection() +{ + d = new QHelpDataFilterSectionData(); +} + +/*! + Adds the filter attribute \a filter to the filter attributes of + this section. +*/ +void QHelpDataFilterSection::addFilterAttribute(const QString &filter) +{ + d->filterAttributes.append(filter); +} + +/*! + Returns a list of all filter attributes defined for this section. +*/ +QStringList QHelpDataFilterSection::filterAttributes() const +{ + return d->filterAttributes; +} + +/*! + Adds the index item \a index to the list of indices. +*/ +void QHelpDataFilterSection::addIndex(const QHelpDataIndexItem &index) +{ + d->indices.append(index); +} + +/*! + Sets the filter sections list of indices to \a indices. +*/ +void QHelpDataFilterSection::setIndices(const QList<QHelpDataIndexItem> &indices) +{ + d->indices = indices; +} + +/*! + Returns the list of indices. +*/ +QList<QHelpDataIndexItem> QHelpDataFilterSection::indices() const +{ + return d->indices; +} + +/*! + Adds the top level content item \a content to the filter section. +*/ +void QHelpDataFilterSection::addContent(QHelpDataContentItem *content) +{ + d->contents.append(content); +} + +/*! + Sets the list of top level content items of the filter section to + \a contents. +*/ +void QHelpDataFilterSection::setContents(const QList<QHelpDataContentItem*> &contents) +{ + qDeleteAll(d->contents); + d->contents = contents; +} + +/*! + Returns a list of top level content items. +*/ +QList<QHelpDataContentItem*> QHelpDataFilterSection::contents() const +{ + return d->contents; +} + +/*! + Adds the file \a file to the filter section. +*/ +void QHelpDataFilterSection::addFile(const QString &file) +{ + d->files.append(file); +} + +/*! + Set the list of files to \a files. +*/ +void QHelpDataFilterSection::setFiles(const QStringList &files) +{ + d->files = files; +} + +/*! + Returns the list of files. +*/ +QStringList QHelpDataFilterSection::files() const +{ + return d->files; +} + +/*! + \internal + \class QHelpDataInterface + \since 4.4 +*/ + +/*! + \fn QHelpDataInterface::QHelpDataInterface() + + Constructs a new help data interface. +*/ + +/*! + \fn QHelpDataInterface::~QHelpDataInterface() + + Destroys the help data interface. +*/ + +/*! + \fn QString QHelpDataInterface::namespaceName() const = 0 + + Returns the namespace name of the help data set. +*/ + +/*! + \fn QString QHelpDataInterface::virtualFolder() const = 0 + + Returns the virtual folder of the help data set. +*/ + +/*! + \fn QList<QHelpDataCustomFilter> QHelpDataInterface::customFilters () const = 0 + + Returns a list of custom filters. Defining custom filters is optional. +*/ + +/*! + \fn QList<QHelpDataFilterSection> QHelpDataInterface::filterSections() const = 0 + + Returns a list of filter sections. +*/ + +/*! + \fn QMap<QString, QVariant> QHelpDataInterface::metaData() const = 0 + + Returns a map of meta data. A meta data item can hold almost any data + and is identified by its name. +*/ + +/*! + \fn QString QHelpDataInterface::rootPath() const = 0 + + Returns the root file path of the documentation data. All referenced file + path or links of content items are relative to this path. +*/ + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpdatainterface_p.h b/tools/assistant/lib/qhelpdatainterface_p.h new file mode 100644 index 0000000..2d05cc6 --- /dev/null +++ b/tools/assistant/lib/qhelpdatainterface_p.h @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPDATAINTERFACE_H +#define QHELPDATAINTERFACE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhelp_global.h" + +#include <QtCore/QStringList> +#include <QtCore/QSharedData> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QHELP_EXPORT QHelpDataContentItem +{ +public: + QHelpDataContentItem(QHelpDataContentItem *parent, const QString &title, + const QString &reference); + ~QHelpDataContentItem(); + + QString title() const; + QString reference() const; + QList<QHelpDataContentItem*> children() const; + +private: + QString m_title; + QString m_reference; + QList<QHelpDataContentItem*> m_children; +}; + +struct QHELP_EXPORT QHelpDataIndexItem { + QHelpDataIndexItem() {} + QHelpDataIndexItem(const QString &n, const QString &id, const QString &r) + : name(n), identifier(id), reference(r) {} + + QString name; + QString identifier; + QString reference; + + bool operator==(const QHelpDataIndexItem & other) const; +}; + +class QHelpDataFilterSectionData : public QSharedData +{ +public: + ~QHelpDataFilterSectionData() + { + qDeleteAll(contents); + } + + QStringList filterAttributes; + QList<QHelpDataIndexItem> indices; + QList<QHelpDataContentItem*> contents; + QStringList files; +}; + +class QHELP_EXPORT QHelpDataFilterSection +{ +public: + QHelpDataFilterSection(); + + void addFilterAttribute(const QString &filter); + QStringList filterAttributes() const; + + void addIndex(const QHelpDataIndexItem &index); + void setIndices(const QList<QHelpDataIndexItem> &indices); + QList<QHelpDataIndexItem> indices() const; + + void addContent(QHelpDataContentItem *content); + void setContents(const QList<QHelpDataContentItem*> &contents); + QList<QHelpDataContentItem*> contents() const; + + void addFile(const QString &file); + void setFiles(const QStringList &files); + QStringList files() const; + +private: + QSharedDataPointer<QHelpDataFilterSectionData> d; +}; + +struct QHELP_EXPORT QHelpDataCustomFilter { + QStringList filterAttributes; + QString name; +}; + +class QHELP_EXPORT QHelpDataInterface +{ +public: + QHelpDataInterface() {} + virtual ~QHelpDataInterface() {} + + virtual QString namespaceName() const = 0; + virtual QString virtualFolder() const = 0; + virtual QList<QHelpDataCustomFilter> customFilters() const = 0; + virtual QList<QHelpDataFilterSection> filterSections() const = 0; + virtual QMap<QString, QVariant> metaData() const = 0; + virtual QString rootPath() const = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QHELPDATAINTERFACE_H diff --git a/tools/assistant/lib/qhelpdbreader.cpp b/tools/assistant/lib/qhelpdbreader.cpp new file mode 100644 index 0000000..76994a7 --- /dev/null +++ b/tools/assistant/lib/qhelpdbreader.cpp @@ -0,0 +1,580 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpdbreader_p.h" +#include "qhelp_global.h" + +#include <QtCore/QVariant> +#include <QtCore/QFile> +#include <QtSql/QSqlError> +#include <QtSql/QSqlQuery> + +QT_BEGIN_NAMESPACE + +QHelpDBReader::QHelpDBReader(const QString &dbName) + : QObject(0) +{ + initObject(dbName, + QHelpGlobal::uniquifyConnectionName(QLatin1String("QHelpDBReader"), + this)); +} + +QHelpDBReader::QHelpDBReader(const QString &dbName, const QString &uniqueId, + QObject *parent) + : QObject(parent) +{ + initObject(dbName, uniqueId); +} + +void QHelpDBReader::initObject(const QString &dbName, const QString &uniqueId) +{ + m_dbName = dbName; + m_uniqueId = uniqueId; + m_initDone = false; + m_query = 0; + m_useAttributesCache = false; +} + +QHelpDBReader::~QHelpDBReader() +{ + if (m_initDone) { + delete m_query; + QSqlDatabase::removeDatabase(m_uniqueId); + } +} + +bool QHelpDBReader::init() +{ + if (m_initDone) + return true; + + if (!QFile::exists(m_dbName)) + return false; + + QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), m_uniqueId); + db.setDatabaseName(m_dbName); + if (!db.open()) { + m_error = tr("Cannot open database '%1' '%2': %3").arg(m_dbName, m_uniqueId, db.lastError().text()); + QSqlDatabase::removeDatabase(m_uniqueId); + return false; + } + + m_initDone = true; + m_query = new QSqlQuery(db); + + return true; +} + +QString QHelpDBReader::databaseName() const +{ + return m_dbName; +} + +QString QHelpDBReader::errorMessage() const +{ + return m_error; +} + +QString QHelpDBReader::namespaceName() const +{ + if (!m_namespace.isEmpty()) + return m_namespace; + if (m_query) { + m_query->exec(QLatin1String("SELECT Name FROM NamespaceTable")); + if (m_query->next()) + m_namespace = m_query->value(0).toString(); + } + return m_namespace; +} + +QString QHelpDBReader::virtualFolder() const +{ + if (m_query) { + m_query->exec(QLatin1String("SELECT Name FROM FolderTable WHERE Id=1")); + if (m_query->next()) + return m_query->value(0).toString(); + } + return QString(); +} + +QList<QStringList> QHelpDBReader::filterAttributeSets() const +{ + QList<QStringList> result; + if (m_query) { + m_query->exec(QLatin1String("SELECT a.Id, b.Name FROM FileAttributeSetTable a, " + "FilterAttributeTable b WHERE a.FilterAttributeId=b.Id ORDER BY a.Id")); + int oldId = -1; + while (m_query->next()) { + int id = m_query->value(0).toInt(); + if (id != oldId) { + result.append(QStringList()); + oldId = id; + } + result.last().append(m_query->value(1).toString()); + } + } + return result; +} + +bool QHelpDBReader::fileExists(const QString &virtualFolder, + const QString &filePath, + const QStringList &filterAttributes) const +{ + if (virtualFolder.isEmpty() || filePath.isEmpty() || !m_query) + return false; + +//SELECT COUNT(a.Name) FROM FileNameTable a, FolderTable b, FileFilterTable c, FilterAttributeTable d WHERE a.FolderId=b.Id AND b.Name='qtdoc' AND a.Name='qstring.html' AND a.FileId=c.FileId AND c.FilterAttributeId=d.Id AND d.Name='qtrefdoc' + + QString query; + namespaceName(); + if (filterAttributes.isEmpty()) { + query = QString(QLatin1String("SELECT COUNT(a.Name) FROM FileNameTable a, FolderTable b " + "WHERE a.FolderId=b.Id AND b.Name=\'%1\' AND a.Name=\'%2\'")).arg(quote(virtualFolder)).arg(quote(filePath)); + } else { + query = QString(QLatin1String("SELECT COUNT(a.Name) FROM FileNameTable a, FolderTable b, " + "FileFilterTable c, FilterAttributeTable d WHERE a.FolderId=b.Id " + "AND b.Name=\'%1\' AND a.Name=\'%2\' AND a.FileId=c.FileId AND " + "c.FilterAttributeId=d.Id AND d.Name=\'%3\'")) + .arg(quote(virtualFolder)).arg(quote(filePath)) + .arg(quote(filterAttributes.first())); + for (int i=1; i<filterAttributes.count(); ++i) { + query.append(QString(QLatin1String(" INTERSECT SELECT COUNT(a.Name) FROM FileNameTable a, " + "FolderTable b, FileFilterTable c, FilterAttributeTable d WHERE a.FolderId=b.Id " + "AND b.Name=\'%1\' AND a.Name=\'%2\' AND a.FileId=c.FileId AND " + "c.FilterAttributeId=d.Id AND d.Name=\'%3\'")) + .arg(quote(virtualFolder)).arg(quote(filePath)) + .arg(quote(filterAttributes.at(i)))); + } + } + m_query->exec(query); + if (m_query->next() && m_query->isValid() && m_query->value(0).toInt()) + return true; + return false; +} + +QByteArray QHelpDBReader::fileData(const QString &virtualFolder, + const QString &filePath) const +{ + QByteArray ba; + if (virtualFolder.isEmpty() || filePath.isEmpty() || !m_query) + return ba; + + namespaceName(); + m_query->prepare(QLatin1String("SELECT a.Data FROM FileDataTable a, FileNameTable b, FolderTable c, " + "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(2, virtualFolder); + m_query->bindValue(3, m_namespace); + m_query->exec(); + if (m_query->next() && m_query->isValid()) + ba = qUncompress(m_query->value(0).toByteArray()); + return ba; +} + +QStringList QHelpDBReader::customFilters() const +{ + QStringList lst; + if (m_query) { + m_query->exec(QLatin1String("SELECT Name FROM FilterNameTable")); + while (m_query->next()) + lst.append(m_query->value(0).toString()); + } + return lst; +} + +QStringList QHelpDBReader::filterAttributes(const QString &filterName) const +{ + QStringList lst; + if (m_query) { + if (filterName.isEmpty()) { + m_query->prepare(QLatin1String("SELECT Name FROM FilterAttributeTable")); + } else { + m_query->prepare(QLatin1String("SELECT a.Name FROM FilterAttributeTable a, " + "FilterTable b, FilterNameTable c WHERE c.Name=? " + "AND c.Id=b.NameId AND b.FilterAttributeId=a.Id")); + m_query->bindValue(0, filterName); + } + m_query->exec(); + while (m_query->next()) + lst.append(m_query->value(0).toString()); + } + return lst; +} + +QStringList QHelpDBReader::indicesForFilter(const QStringList &filterAttributes) const +{ + QStringList indices; + if (!m_query) + return indices; + + //SELECT DISTINCT a.Name FROM IndexTable a, IndexFilterTable b, FilterAttributeTable c WHERE a.Id=b.IndexId AND b.FilterAttributeId=c.Id AND c.Name in ('4.2.3', 'qt') + + QString query; + if (filterAttributes.isEmpty()) { + query = QLatin1String("SELECT DISTINCT Name FROM IndexTable"); + } else { + query = QString(QLatin1String("SELECT DISTINCT a.Name FROM IndexTable a, " + "IndexFilterTable b, FilterAttributeTable c WHERE a.Id=b.IndexId " + "AND b.FilterAttributeId=c.Id AND c.Name='%1'")).arg(quote(filterAttributes.first())); + for (int i=1; i<filterAttributes.count(); ++i) { + query.append(QString(QLatin1String(" INTERSECT SELECT DISTINCT a.Name FROM IndexTable a, " + "IndexFilterTable b, FilterAttributeTable c WHERE a.Id=b.IndexId " + "AND b.FilterAttributeId=c.Id AND c.Name='%1'")) + .arg(quote(filterAttributes.at(i)))); + } + } + + m_query->exec(query); + while (m_query->next()) { + if (!m_query->value(0).toString().isEmpty()) + indices.append(m_query->value(0).toString()); + } + return indices; +} + +void QHelpDBReader::linksForKeyword(const QString &keyword, const QStringList &filterAttributes, + QMap<QString, QUrl> &linkMap) const +{ + if (!m_query) + return; + + QString query; + if (filterAttributes.isEmpty()) { + query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor " + "FROM IndexTable a, FileNameTable d, " + "FolderTable e, NamespaceTable f WHERE " + "a.FileId=d.FileId AND d.FolderId=e.Id AND a.NamespaceId=f.Id " + "AND a.Name='%1'")).arg(quote(keyword)); + } else if (m_useAttributesCache) { + query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor, a.Id " + "FROM IndexTable a, " + "FileNameTable d, FolderTable e, NamespaceTable f WHERE " + "a.FileId=d.FileId AND d.FolderId=e.Id " + "AND a.NamespaceId=f.Id AND a.Name='%1'")) + .arg(quote(keyword)); + m_query->exec(query); + while (m_query->next()) { + if (m_indicesCache.contains(m_query->value(5).toInt())) { + linkMap.insertMulti(m_query->value(0).toString(), buildQUrl(m_query->value(1).toString(), + m_query->value(2).toString(), m_query->value(3).toString(), + m_query->value(4).toString())); + } + } + return; + } else { + query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor " + "FROM IndexTable a, IndexFilterTable b, FilterAttributeTable c, " + "FileNameTable d, FolderTable e, NamespaceTable f " + "WHERE a.FileId=d.FileId AND d.FolderId=e.Id " + "AND a.NamespaceId=f.Id AND b.IndexId=a.Id AND b.FilterAttributeId=c.Id " + "AND a.Name='%1' AND c.Name='%2'")).arg(quote(keyword)) + .arg(quote(filterAttributes.first())); + for (int i=1; i<filterAttributes.count(); ++i) { + query.append(QString(QLatin1String(" INTERSECT SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor " + "FROM IndexTable a, IndexFilterTable b, FilterAttributeTable c, " + "FileNameTable d, FolderTable e, NamespaceTable f " + "WHERE a.FileId=d.FileId AND d.FolderId=e.Id " + "AND a.NamespaceId=f.Id AND b.IndexId=a.Id AND b.FilterAttributeId=c.Id " + "AND a.Name='%1' AND c.Name='%2'")).arg(quote(keyword)) + .arg(quote(filterAttributes.at(i)))); + } + } + + QString title; + m_query->exec(query); + while (m_query->next()) { + title = m_query->value(0).toString(); + if (title.isEmpty()) // generate a title + corresponding path + title = keyword + QLatin1String(" : ") + m_query->value(3).toString(); + linkMap.insertMulti(title, buildQUrl(m_query->value(1).toString(), + m_query->value(2).toString(), m_query->value(3).toString(), + m_query->value(4).toString())); + } +} + +void QHelpDBReader::linksForIdentifier(const QString &id, + const QStringList &filterAttributes, + QMap<QString, QUrl> &linkMap) const +{ + if (!m_query) + return; + + QString query; + if (filterAttributes.isEmpty()) { + query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor " + "FROM IndexTable a, FileNameTable d, FolderTable e, " + "NamespaceTable f WHERE a.FileId=d.FileId AND " + "d.FolderId=e.Id AND a.NamespaceId=f.Id AND a.Identifier='%1'")) + .arg(quote(id)); + } else if (m_useAttributesCache) { + query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor, a.Id " + "FROM IndexTable a," + "FileNameTable d, FolderTable e, NamespaceTable f WHERE " + "a.FileId=d.FileId AND d.FolderId=e.Id " + "AND a.NamespaceId=f.Id AND a.Identifier='%1'")) + .arg(quote(id)); + m_query->exec(query); + while (m_query->next()) { + if (m_indicesCache.contains(m_query->value(5).toInt())) { + linkMap.insertMulti(m_query->value(0).toString(), buildQUrl(m_query->value(1).toString(), + m_query->value(2).toString(), m_query->value(3).toString(), + m_query->value(4).toString())); + } + } + return; + } else { + query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor " + "FROM IndexTable a, IndexFilterTable b, FilterAttributeTable c, " + "FileNameTable d, FolderTable e, NamespaceTable f " + "WHERE a.FileId=d.FileId AND d.FolderId=e.Id " + "AND a.NamespaceId=f.Id AND b.IndexId=a.Id AND b.FilterAttributeId=c.Id " + "AND a.Identifier='%1' AND c.Name='%2'")).arg(quote(id)) + .arg(quote(filterAttributes.first())); + for (int i=0; i<filterAttributes.count(); ++i) { + query.append(QString(QLatin1String(" INTERSECT SELECT d.Title, f.Name, e.Name, " + "d.Name, a.Anchor FROM IndexTable a, IndexFilterTable b, " + "FilterAttributeTable c, FileNameTable d, " + "FolderTable e, NamespaceTable f WHERE " + "a.FileId=d.FileId AND d.FolderId=e.Id AND a.NamespaceId=f.Id " + "AND b.IndexId=a.Id AND b.FilterAttributeId=c.Id AND " + "a.Identifier='%1' AND c.Name='%2'")).arg(quote(id)) + .arg(quote(filterAttributes.at(i)))); + } + } + + m_query->exec(query); + while (m_query->next()) { + linkMap.insertMulti(m_query->value(0).toString(), buildQUrl(m_query->value(1).toString(), + m_query->value(2).toString(), m_query->value(3).toString(), + m_query->value(4).toString())); + } +} + +QUrl QHelpDBReader::buildQUrl(const QString &ns, const QString &folder, + const QString &relFileName, const QString &anchor) const +{ + QUrl url; + url.setScheme(QLatin1String("qthelp")); + url.setAuthority(ns); + url.setPath(folder + QLatin1Char('/') + relFileName); + url.setFragment(anchor); + return url; +} + +QList<QByteArray> QHelpDBReader::contentsForFilter(const QStringList &filterAttributes) const +{ + QList<QByteArray> contents; + if (!m_query) + return contents; + + //SELECT DISTINCT a.Data FROM ContentsTable a, ContentsFilterTable b, FilterAttributeTable c WHERE a.Id=b.ContentsId AND b.FilterAttributeId=c.Id AND c.Name='qt' INTERSECT SELECT DISTINCT a.Data FROM ContentsTable a, ContentsFilterTable b, FilterAttributeTable c WHERE a.Id=b.ContentsId AND b.FilterAttributeId=c.Id AND c.Name='3.3.8'; + + QString query; + if (filterAttributes.isEmpty()) { + query = QLatin1String("SELECT Data from ContentsTable"); + } else { + query = QString(QLatin1String("SELECT a.Data FROM ContentsTable a, " + "ContentsFilterTable b, FilterAttributeTable c " + "WHERE a.Id=b.ContentsId AND b.FilterAttributeId=c.Id " + "AND c.Name='%1'")).arg(quote(filterAttributes.first())); + for (int i=1; i<filterAttributes.count(); ++i) { + query.append(QString(QLatin1String(" INTERSECT SELECT a.Data FROM ContentsTable a, " + "ContentsFilterTable b, FilterAttributeTable c " + "WHERE a.Id=b.ContentsId AND b.FilterAttributeId=c.Id " + "AND c.Name='%1'")).arg(quote(filterAttributes.at(i)))); + } + } + + m_query->exec(query); + while (m_query->next()) { + contents.append(m_query->value(0).toByteArray()); + } + return contents; +} + +QUrl QHelpDBReader::urlOfPath(const QString &relativePath) const +{ + QUrl url; + if (!m_query) + return url; + + m_query->exec(QLatin1String("SELECT a.Name, b.Name FROM NamespaceTable a, " + "FolderTable b WHERE a.id=b.NamespaceId and a.Id=1")); + if (m_query->next()) { + QString rp = relativePath; + QString anchor; + int i = rp.indexOf(QLatin1Char('#')); + if (i > -1) { + rp = relativePath.left(i); + anchor = relativePath.mid(i+1); + } + url = buildQUrl(m_query->value(0).toString(), + m_query->value(1).toString(), rp, anchor); + } + return url; +} + +QStringList QHelpDBReader::files(const QStringList &filterAttributes, + const QString &extensionFilter) const +{ + QStringList lst; + if (!m_query) + return lst; + + QString query; + QString extension; + if (!extensionFilter.isEmpty()) + extension = QString(QLatin1String("AND b.Name like \'%.%1\'")).arg(extensionFilter); + + if (filterAttributes.isEmpty()) { + query = QString(QLatin1String("SELECT a.Name, b.Name FROM FolderTable a, " + "FileNameTable b WHERE b.FolderId=a.Id %1")) + .arg(extension); + } else { + query = QString(QLatin1String("SELECT a.Name, b.Name FROM FolderTable a, " + "FileNameTable b, FileFilterTable c, FilterAttributeTable d " + "WHERE b.FolderId=a.Id AND b.FileId=c.FileId " + "AND c.FilterAttributeId=d.Id AND d.Name=\'%1\' %2")) + .arg(quote(filterAttributes.first())).arg(extension); + for (int i=1; i<filterAttributes.count(); ++i) { + query.append(QString(QLatin1String(" INTERSECT SELECT a.Name, b.Name FROM " + "FolderTable a, FileNameTable b, FileFilterTable c, " + "FilterAttributeTable d WHERE b.FolderId=a.Id AND " + "b.FileId=c.FileId AND c.FilterAttributeId=d.Id AND " + "d.Name=\'%1\' %2")).arg(quote(filterAttributes.at(i))) + .arg(extension)); + } + } + m_query->exec(query); + while (m_query->next()) { + lst.append(m_query->value(0).toString() + QLatin1Char('/') + + m_query->value(1).toString()); + } + + return lst; +} + +QVariant QHelpDBReader::metaData(const QString &name) const +{ + QVariant v; + if (!m_query) + return v; + + m_query->prepare(QLatin1String("SELECT COUNT(Value), Value FROM MetaDataTable " + "WHERE Name=?")); + m_query->bindValue(0, name); + if (m_query->exec() && m_query->next() + && m_query->value(0).toInt() == 1) + v = m_query->value(1); + return v; +} + +QString QHelpDBReader::mergeList(const QStringList &list) const +{ + QString str; + foreach (QString s, list) + str.append(QLatin1Char('\'') + quote(s) + QLatin1String("\', ")); + if (str.endsWith(QLatin1String(", "))) + str = str.left(str.length()-2); + return str; +} + +QString QHelpDBReader::quote(const QString &string) const +{ + QString s = string; + s.replace(QLatin1Char('\''), QLatin1String("\'\'")); + return s; +} + +QSet<int> QHelpDBReader::indexIds(const QStringList &attributes) const +{ + QSet<int> ids; + + if (attributes.isEmpty()) + return ids; + + QString query = QString(QLatin1String("SELECT a.IndexId FROM IndexFilterTable a, " + "FilterAttributeTable b WHERE a.FilterAttributeId=b.Id " + "AND b.Name='%1'")).arg(attributes.first()); + for (int i=0; i<attributes.count(); ++i) { + query.append(QString(QLatin1String(" INTERSECT SELECT a.IndexId FROM " + "IndexFilterTable a, FilterAttributeTable b WHERE " + "a.FilterAttributeId=b.Id AND b.Name='%1'")) + .arg(attributes.at(i))); + } + + if (!m_query->exec(query)) + return ids; + + while (m_query->next()) + ids.insert(m_query->value(0).toInt()); + + return ids; +} + +bool QHelpDBReader::createAttributesCache(const QStringList &attributes, + const QSet<int> &indexIds) +{ + m_useAttributesCache = false; + + if (attributes.count() < 2) { + m_viewAttributes.clear(); + return true; + } + + bool needUpdate = !m_viewAttributes.count(); + + foreach (QString s, attributes) + m_viewAttributes.remove(s); + + if (m_viewAttributes.count() || needUpdate) { + m_viewAttributes.clear(); + m_indicesCache = indexIds; + } + foreach (QString s, attributes) + m_viewAttributes.insert(s); + m_useAttributesCache = true; + return true; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpdbreader_p.h b/tools/assistant/lib/qhelpdbreader_p.h new file mode 100644 index 0000000..08fc382 --- /dev/null +++ b/tools/assistant/lib/qhelpdbreader_p.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPDBREADER_H +#define QHELPDBREADER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QObject> +#include <QtCore/QStringList> +#include <QtCore/QUrl> +#include <QtCore/QByteArray> +#include <QtCore/QSet> + +QT_BEGIN_NAMESPACE + +class QSqlQuery; + +class QHelpDBReader : public QObject +{ + Q_OBJECT + +public: + QHelpDBReader(const QString &dbName); + QHelpDBReader(const QString &dbName, const QString &uniqueId, + QObject *parent); + ~QHelpDBReader(); + + bool init(); + + QString errorMessage() const; + + QString databaseName() const; + QString namespaceName() const; + QString virtualFolder() const; + QList<QStringList> filterAttributeSets() const; + QStringList files(const QStringList &filterAttributes, + const QString &extensionFilter = QString()) const; + bool fileExists(const QString &virtualFolder, const QString &filePath, + const QStringList &filterAttributes = QStringList()) const; + QByteArray fileData(const QString &virtualFolder, + const QString &filePath) const; + + QStringList customFilters() const; + QStringList filterAttributes(const QString &filterName = QString()) const; + QStringList indicesForFilter(const QStringList &filterAttributes) const; + void linksForKeyword(const QString &keyword, const QStringList &filterAttributes, + QMap<QString, QUrl> &linkMap) const; + + void linksForIdentifier(const QString &id, const QStringList &filterAttributes, + QMap<QString, QUrl> &linkMap) const; + + QList<QByteArray> contentsForFilter(const QStringList &filterAttributes) const; + QUrl urlOfPath(const QString &relativePath) const; + + QSet<int> indexIds(const QStringList &attributes) const; + bool createAttributesCache(const QStringList &attributes, + const QSet<int> &indexIds); + QVariant metaData(const QString &name) const; + +private: + void initObject(const QString &dbName, const QString &uniqueId); + QUrl buildQUrl(const QString &ns, const QString &folder, + const QString &relFileName, const QString &anchor) const; + QString mergeList(const QStringList &list) const; + QString quote(const QString &string) const; + + bool m_initDone; + QString m_dbName; + QString m_uniqueId; + QString m_error; + QSqlQuery *m_query; + mutable QString m_namespace; + QSet<QString> m_viewAttributes; + bool m_useAttributesCache; + QSet<int> m_indicesCache; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/lib/qhelpengine.cpp b/tools/assistant/lib/qhelpengine.cpp new file mode 100644 index 0000000..6a603b7 --- /dev/null +++ b/tools/assistant/lib/qhelpengine.cpp @@ -0,0 +1,212 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpengine.h" +#include "qhelpengine_p.h" +#include "qhelpdbreader_p.h" +#include "qhelpcontentwidget.h" +#include "qhelpindexwidget.h" +#include "qhelpsearchengine.h" +#include "qhelpcollectionhandler_p.h" + +#include <QtCore/QDir> +#include <QtCore/QFile> +#include <QtCore/QLibrary> +#include <QtCore/QPluginLoader> +#include <QtGui/QApplication> +#include <QtSql/QSqlQuery> + +QT_BEGIN_NAMESPACE + +QHelpEnginePrivate::QHelpEnginePrivate() + : QHelpEngineCorePrivate() + , contentModel(0) + , contentWidget(0) + , indexModel(0) + , indexWidget(0) + , searchEngine(0) +{ +} + +QHelpEnginePrivate::~QHelpEnginePrivate() +{ +} + +void QHelpEnginePrivate::init(const QString &collectionFile, + QHelpEngineCore *helpEngineCore) +{ + QHelpEngineCorePrivate::init(collectionFile, helpEngineCore); + + contentModel = new QHelpContentModel(this); + indexModel = new QHelpIndexModel(this); + + connect(helpEngineCore, SIGNAL(setupFinished()), + this, SLOT(applyCurrentFilter())); + connect(helpEngineCore, SIGNAL(currentFilterChanged(const QString&)), + this, SLOT(applyCurrentFilter())); + +} + +void QHelpEnginePrivate::applyCurrentFilter() +{ + if (!error.isEmpty()) + return; + contentModel->createContents(currentFilter); + indexModel->createIndex(currentFilter); +} + +void QHelpEnginePrivate::setContentsWidgetBusy() +{ + contentWidget->setCursor(Qt::WaitCursor); +} + +void QHelpEnginePrivate::unsetContentsWidgetBusy() +{ + contentWidget->unsetCursor(); +} + +void QHelpEnginePrivate::setIndexWidgetBusy() +{ + indexWidget->setCursor(Qt::WaitCursor); +} + +void QHelpEnginePrivate::unsetIndexWidgetBusy() +{ + indexWidget->unsetCursor(); +} + +void QHelpEnginePrivate::stopDataCollection() +{ + contentModel->invalidateContents(true); + indexModel->invalidateIndex(true); +} + + + +/*! + \class QHelpEngine + \since 4.4 + \inmodule QtHelp + \brief The QHelpEngine class provides access to contents and + indices of the help engine. + + +*/ + +/*! + Constructs a new help engine with the given \a parent. The help + engine uses the information stored in the \a collectionFile for + providing help. If the collection file does not already exist, + it will be created. +*/ +QHelpEngine::QHelpEngine(const QString &collectionFile, QObject *parent) + : QHelpEngineCore(d = new QHelpEnginePrivate(), parent) +{ + d->init(collectionFile, this); +} + +/*! + Destroys the help engine object. +*/ +QHelpEngine::~QHelpEngine() +{ + d->stopDataCollection(); +} + +/*! + Returns the content model. +*/ +QHelpContentModel *QHelpEngine::contentModel() const +{ + return d->contentModel; +} + +/*! + Returns the index model. +*/ +QHelpIndexModel *QHelpEngine::indexModel() const +{ + return d->indexModel; +} + +/*! + Returns the content widget. +*/ +QHelpContentWidget *QHelpEngine::contentWidget() +{ + if (!d->contentWidget) { + d->contentWidget = new QHelpContentWidget(); + d->contentWidget->setModel(d->contentModel); + connect(d->contentModel, SIGNAL(contentsCreationStarted()), + d, SLOT(setContentsWidgetBusy())); + connect(d->contentModel, SIGNAL(contentsCreated()), + d, SLOT(unsetContentsWidgetBusy())); + } + return d->contentWidget; +} + +/*! + Returns the index widget. +*/ +QHelpIndexWidget *QHelpEngine::indexWidget() +{ + if (!d->indexWidget) { + d->indexWidget = new QHelpIndexWidget(); + d->indexWidget->setModel(d->indexModel); + connect(d->indexModel, SIGNAL(indexCreationStarted()), + d, SLOT(setIndexWidgetBusy())); + connect(d->indexModel, SIGNAL(indexCreated()), + d, SLOT(unsetIndexWidgetBusy())); + } + return d->indexWidget; +} + +/*! + Returns the default search engine. +*/ +QHelpSearchEngine* QHelpEngine::searchEngine() +{ + if (!d->searchEngine) + d->searchEngine = new QHelpSearchEngine(this, this); + return d->searchEngine; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpengine.h b/tools/assistant/lib/qhelpengine.h new file mode 100644 index 0000000..9c80ff3 --- /dev/null +++ b/tools/assistant/lib/qhelpengine.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPENGINE_H +#define QHELPENGINE_H + +#include <QtHelp/qhelpenginecore.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Help) + +class QHelpContentModel; +class QHelpContentWidget; +class QHelpIndexModel; +class QHelpIndexWidget; +class QHelpEnginePrivate; +class QHelpSearchEngine; + +class QHELP_EXPORT QHelpEngine : public QHelpEngineCore +{ + Q_OBJECT + +public: + QHelpEngine(const QString &collectionFile, QObject *parent = 0); + ~QHelpEngine(); + + QHelpContentModel *contentModel() const; + QHelpIndexModel *indexModel() const; + + QHelpContentWidget *contentWidget(); + QHelpIndexWidget *indexWidget(); + + QHelpSearchEngine *searchEngine(); + +private: + QHelpEnginePrivate *d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/tools/assistant/lib/qhelpengine_p.h b/tools/assistant/lib/qhelpengine_p.h new file mode 100644 index 0000000..287329a --- /dev/null +++ b/tools/assistant/lib/qhelpengine_p.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPENGINE_P_H +#define QHELPENGINE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QMap> +#include <QtCore/QStringList> +#include <QtCore/QObject> + +QT_BEGIN_NAMESPACE + +class QSqlQuery; + +class QHelpEngineCore; +class QHelpDBReader; +class QHelpContentModel; +class QHelpContentWidget; +class QHelpIndexModel; +class QHelpIndexWidget; +class QHelpSearchEngine; +class QHelpCollectionHandler; + +class QHelpEngineCorePrivate : public QObject +{ + Q_OBJECT + +public: + QHelpEngineCorePrivate(); + virtual ~QHelpEngineCorePrivate(); + + virtual void init(const QString &collectionFile, + QHelpEngineCore *helpEngineCore); + + void clearMaps(); + bool setup(); + + QMap<QString, QHelpDBReader*> readerMap; + QMap<QString, QHelpDBReader*> fileNameReaderMap; + QMultiMap<QString, QHelpDBReader*> virtualFolderMap; + QStringList orderedFileNameList; + + QHelpCollectionHandler *collectionHandler; + QString currentFilter; + QString error; + bool needsSetup; + bool autoSaveFilter; + +protected: + QHelpEngineCore *q; + +private slots: + void errorReceived(const QString &msg); +}; + + +class QHelpEnginePrivate : public QHelpEngineCorePrivate +{ + Q_OBJECT + +public: + QHelpEnginePrivate(); + ~QHelpEnginePrivate(); + + void init(const QString &collectionFile, + QHelpEngineCore *helpEngineCore); + + QHelpContentModel *contentModel; + QHelpContentWidget *contentWidget; + + QHelpIndexModel *indexModel; + QHelpIndexWidget *indexWidget; + + QHelpSearchEngine *searchEngine; + + void stopDataCollection(); + + friend class QHelpContentProvider; + friend class QHelpContentModel; + friend class QHelpIndexProvider; + friend class QHelpIndexModel; + +public slots: + void setContentsWidgetBusy(); + void unsetContentsWidgetBusy(); + void setIndexWidgetBusy(); + void unsetIndexWidgetBusy(); + +private slots: + void applyCurrentFilter(); +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/lib/qhelpenginecore.cpp b/tools/assistant/lib/qhelpenginecore.cpp new file mode 100644 index 0000000..85bd9fd --- /dev/null +++ b/tools/assistant/lib/qhelpenginecore.cpp @@ -0,0 +1,727 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpenginecore.h" +#include "qhelpengine_p.h" +#include "qhelpdbreader_p.h" +#include "qhelpcollectionhandler_p.h" + +#include <QtCore/QDir> +#include <QtCore/QFile> +#include <QtCore/QLibrary> +#include <QtCore/QPluginLoader> +#include <QtCore/QFileInfo> +#include <QtCore/QThread> +#include <QtGui/QApplication> +#include <QtSql/QSqlQuery> + +QT_BEGIN_NAMESPACE + +QHelpEngineCorePrivate::QHelpEngineCorePrivate() +{ + QHelpGlobal::uniquifyConnectionName(QString(), this); + autoSaveFilter = true; +} + +void QHelpEngineCorePrivate::init(const QString &collectionFile, + QHelpEngineCore *helpEngineCore) +{ + q = helpEngineCore; + collectionHandler = new QHelpCollectionHandler(collectionFile, helpEngineCore); + connect(collectionHandler, SIGNAL(error(const QString&)), + this, SLOT(errorReceived(const QString&))); + needsSetup = true; +} + +QHelpEngineCorePrivate::~QHelpEngineCorePrivate() +{ + delete collectionHandler; + clearMaps(); +} + +void QHelpEngineCorePrivate::clearMaps() +{ + QMap<QString, QHelpDBReader*>::iterator it = readerMap.begin(); + while (it != readerMap.end()) { + delete it.value(); + ++it; + } + readerMap.clear(); + fileNameReaderMap.clear(); + virtualFolderMap.clear(); + orderedFileNameList.clear(); +} + +bool QHelpEngineCorePrivate::setup() +{ + error.clear(); + if (!needsSetup) + return true; + + needsSetup = false; + emit q->setupStarted(); + clearMaps(); + + if (!collectionHandler->openCollectionFile()) { + emit q->setupFinished(); + return false; + } + + const QHelpCollectionHandler::DocInfoList docList = + collectionHandler->registeredDocumentations(); + QFileInfo fi(collectionHandler->collectionFile()); + QString absFileName; + foreach(const QHelpCollectionHandler::DocInfo &info, docList) { + if (QDir::isAbsolutePath(info.fileName)) { + absFileName = info.fileName; + } else { + absFileName = QFileInfo(fi.absolutePath() + QDir::separator() + info.fileName) + .absoluteFilePath(); + } + QHelpDBReader *reader = new QHelpDBReader(absFileName, + QHelpGlobal::uniquifyConnectionName(info.fileName, this), this); + if (!reader->init()) { + emit q->warning(tr("Cannot open documentation file %1: %2!") + .arg(absFileName, reader->errorMessage())); + continue; + } + + readerMap.insert(info.namespaceName, reader); + fileNameReaderMap.insert(absFileName, reader); + virtualFolderMap.insert(info.folderName, reader); + orderedFileNameList.append(absFileName); + } + q->currentFilter(); + emit q->setupFinished(); + return true; +} + +void QHelpEngineCorePrivate::errorReceived(const QString &msg) +{ + error = msg; +} + + + +/*! + \class QHelpEngineCore + \since 4.4 + \inmodule QtHelp + \brief The QHelpEngineCore class provides the core functionality + of the help system. + + Before the help engine can be used, it must be initialized by + calling setupData(). At the beginning of the setup process the + signal setupStarted() is emitted. From this point on until + the signal setupFinished() is emitted, is the help data in an + undefined meaning unusable state. + + The core help engine can be used to perform different tasks. + By calling linksForIdentifier() the engine returns + urls specifying the file locations inside the help system. The + actual file data can then be retrived by calling fileData(). In + contrast to all other functions in this class, linksForIdentifier() + depends on the currently set custom filter. Depending on the filter, + the function may return different hits. + + Every help engine can contain any number of custom filters. A custom + filter is defined by a name and set of filter attributes and can be + added to the help engine by calling addCustomFilter(). Analogous, + it is removed by calling removeCustomFilter(). customFilters() returns + all defined filters. + + The help engine also offers the possiblity to set and read values + in a persistant way comparable to ini files or Windows registry + entries. For more information see setValue() or value(). + + This class does not offer any GUI components or functionality for + indices or contents. If you need one of those use QHelpEngine + instead. +*/ + +/*! + \fn void QHelpEngineCore::setupStarted() + + This signal is emitted when setup is started. +*/ + +/*! + \fn void QHelpEngineCore::setupFinished() + + This signal is emitted when the setup is complete. +*/ + +/*! + \fn void QHelpEngineCore::currentFilterChanged(const QString &newFilter) + + This signal is emitted when the current filter is changed to + \a newFilter. +*/ + +/*! + \fn void QHelpEngineCore::warning(const QString &msg) + + This signal is emitted when a non critical error occurs. + The warning message is stored in \a msg. +*/ + +/*! + Constructs a new core help engine with a \a parent. The help engine + uses the information stored in the \a collectionFile to provide help. + If the collection file does not exist yet, it'll be created. +*/ +QHelpEngineCore::QHelpEngineCore(const QString &collectionFile, QObject *parent) + : QObject(parent) +{ + d = new QHelpEngineCorePrivate(); + d->init(collectionFile, this); +} + +/*! + \internal +*/ +QHelpEngineCore::QHelpEngineCore(QHelpEngineCorePrivate *helpEngineCorePrivate, + QObject *parent) + : QObject(parent) +{ + d = helpEngineCorePrivate; +} + +/*! + Destructs the help engine. +*/ +QHelpEngineCore::~QHelpEngineCore() +{ + delete d; +} + +/*! + \property QHelpEngineCore::collectionFile + \brief the absolute file name of the collection file currently used. + \since 4.5 + + Setting this property leaves the help engine in an invalid state. It is + important to invoke setupData() or any getter function in order to setup + the help engine again. +*/ +QString QHelpEngineCore::collectionFile() const +{ + return d->collectionHandler->collectionFile(); +} + +void QHelpEngineCore::setCollectionFile(const QString &fileName) +{ + if (fileName == collectionFile()) + return; + + if (d->collectionHandler) { + delete d->collectionHandler; + d->collectionHandler = 0; + d->clearMaps(); + } + d->init(fileName, this); + d->needsSetup = true; +} + +/*! + Sets up the help engine by processing the information found + in the collection file and returns true if successful; otherwise + returns false. + + By calling the function, the help + engine is forced to initialize itself immediately. Most of + the times, this function does not have to be called + explicitly because getter functions which depend on a correctly + set up help engine do that themselves. + + \note \c{qsqlite4.dll} needs to be deployed with the application as the + help system uses the sqlite driver when loading help collections. +*/ +bool QHelpEngineCore::setupData() +{ + d->needsSetup = true; + return d->setup(); +} + +/*! + Creates the file \a fileName and copies all contents from + the current collection file into the newly created file, + and returns true if successful; otherwise returns false. + + The copying process makes sure that file references to Qt + Collection files (\c{.qch}) files are updated accordingly. +*/ +bool QHelpEngineCore::copyCollectionFile(const QString &fileName) +{ + if (!d->setup()) + return false; + return d->collectionHandler->copyCollectionFile(fileName); +} + +/*! + Returns the namespace name defined for the Qt compressed help file (.qch) + specified by its \a documentationFileName. If the file is not valid, an + empty string is returned. + + \sa documentationFileName() +*/ +QString QHelpEngineCore::namespaceName(const QString &documentationFileName) +{ + QHelpDBReader reader(documentationFileName, + QHelpGlobal::uniquifyConnectionName(QLatin1String("GetNamespaceName"), + QThread::currentThread()), 0); + if (reader.init()) + return reader.namespaceName(); + return QString(); +} + +/*! + Registers the Qt compressed help file (.qch) contained in the file + \a documentationFileName. One compressed help file, uniquely + identified by its namespace can only be registered once. + True is returned if the registration was successful, otherwise + false. + + \sa unregisterDocumentation(), error() +*/ +bool QHelpEngineCore::registerDocumentation(const QString &documentationFileName) +{ + d->error.clear(); + d->needsSetup = true; + return d->collectionHandler->registerDocumentation(documentationFileName); +} + +/*! + Unregisters the Qt compressed help file (.qch) identified by its + \a namespaceName from the help collection. Returns true + on success, otherwise false. + + \sa registerDocumentation(), error() +*/ +bool QHelpEngineCore::unregisterDocumentation(const QString &namespaceName) +{ + d->error.clear(); + d->needsSetup = true; + return d->collectionHandler->unregisterDocumentation(namespaceName); +} + +/*! + Returns the absolute file name of the Qt compressed help file (.qch) + identified by the \a namespaceName. If there is no Qt compressed help file + with the specified namespace registered, an empty string is returned. + + \sa namespaceName() +*/ +QString QHelpEngineCore::documentationFileName(const QString &namespaceName) +{ + QString res; + if (!d->setup()) + return res; + const QHelpCollectionHandler::DocInfoList docList = d->collectionHandler->registeredDocumentations(); + foreach(const QHelpCollectionHandler::DocInfo info, docList) { + if (info.namespaceName == namespaceName) { + QFileInfo fi(d->collectionHandler->collectionFile()); + fi.setFile(fi.absolutePath() + QDir::separator() + info.fileName); + res = QDir::cleanPath(fi.absoluteFilePath()); + break; + } + } + return res; +} + +/*! + Returns a list of all registered Qt compressed help files of the current collection file. + The returned names are the namespaces of the registered Qt compressed help files (.qch). +*/ +QStringList QHelpEngineCore::registeredDocumentations() const +{ + QStringList list; + if (!d->setup()) + return list; + const QHelpCollectionHandler::DocInfoList docList = d->collectionHandler->registeredDocumentations(); + foreach(const QHelpCollectionHandler::DocInfo info, docList) { + list.append(info.namespaceName); + } + return list; +} + +/*! + Returns a list of custom filters. + + \sa addCustomFilter(), removeCustomFilter() +*/ +QStringList QHelpEngineCore::customFilters() const +{ + if (!d->setup()) + return QStringList(); + return d->collectionHandler->customFilters(); +} + +/*! + 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. + + \sa customFilters(), removeCustomFilter() +*/ +bool QHelpEngineCore::addCustomFilter(const QString &filterName, + const QStringList &attributes) +{ + d->error.clear(); + d->needsSetup = true; + return d->collectionHandler->addCustomFilter(filterName, + attributes); +} + +/*! + Returns true if the filter \a filterName was removed successfully, + otherwise false. + + \sa addCustomFilter(), customFilters() +*/ +bool QHelpEngineCore::removeCustomFilter(const QString &filterName) +{ + d->error.clear(); + d->needsSetup = true; + return d->collectionHandler->removeCustomFilter(filterName); +} + +/*! + Returns a list of all defined filter attributes. +*/ +QStringList QHelpEngineCore::filterAttributes() const +{ + if (!d->setup()) + return QStringList(); + return d->collectionHandler->filterAttributes(); +} + +/*! + Returns a list of filter attributes used by the custom + filter \a filterName. +*/ +QStringList QHelpEngineCore::filterAttributes(const QString &filterName) const +{ + if (!d->setup()) + return QStringList(); + return d->collectionHandler->filterAttributes(filterName); +} + +/*! + \property QHelpEngineCore::currentFilter + \brief the name of the custom filter currently applied. + \since 4.5 + + Setting this property will save the new custom filter permanently in the + help collection file. To set a custom filter without saving it + permanently, disable the auto save filter mode. + + \sa autoSaveFilter() +*/ +QString QHelpEngineCore::currentFilter() const +{ + if (!d->setup()) + return QString(); + + if (d->currentFilter.isEmpty()) { + QString filter = + d->collectionHandler->customValue(QLatin1String("CurrentFilter"), + QString()).toString(); + if (!filter.isEmpty() + && d->collectionHandler->customFilters().contains(filter)) + d->currentFilter = filter; + } + return d->currentFilter; +} + +void QHelpEngineCore::setCurrentFilter(const QString &filterName) +{ + if (!d->setup() || filterName == d->currentFilter) + return; + d->currentFilter = filterName; + if (d->autoSaveFilter) { + d->collectionHandler->setCustomValue(QLatin1String("CurrentFilter"), + d->currentFilter); + } + emit currentFilterChanged(d->currentFilter); +} + +/*! + Returns a list of filter attributes for the different filter sections + defined in the Qt compressed help file with the given namespace + \a namespaceName. +*/ +QList<QStringList> QHelpEngineCore::filterAttributeSets(const QString &namespaceName) const +{ + if (d->setup()) { + QHelpDBReader *reader = d->readerMap.value(namespaceName); + if (reader) + return reader->filterAttributeSets(); + } + return QList<QStringList>(); +} + +/*! + Returns a list of files contained in the Qt compressed help file \a + namespaceName. The files can be filtered by \a filterAttributes as + well as by their extension \a extensionFilter (e.g. 'html'). +*/ +QList<QUrl> QHelpEngineCore::files(const QString namespaceName, + const QStringList &filterAttributes, + const QString &extensionFilter) +{ + QList<QUrl> res; + if (!d->setup()) + return res; + QHelpDBReader *reader = d->readerMap.value(namespaceName); + if (!reader) { + d->error = tr("The specified namespace does not exist!"); + return res; + } + + QUrl url; + url.setScheme(QLatin1String("qthelp")); + url.setAuthority(namespaceName); + + const QStringList files = reader->files(filterAttributes, extensionFilter); + foreach (const QString file, files) { + url.setPath(QLatin1String("/") + file); + res.append(url); + } + return res; +} + +/*! + Returns an invalid URL if the file \a url cannot be found. + If the file exists, either the same url is returned or a + different url if the file is located in a different namespace + which is merged via a common virtual folder. +*/ +QUrl QHelpEngineCore::findFile(const QUrl &url) const +{ + QUrl res; + if (!d->setup() || !url.isValid() || url.toString().count(QLatin1Char('/')) < 4 + || url.scheme() != QLatin1String("qthelp")) + return res; + + QString ns = url.authority(); + QString filePath = QDir::cleanPath(url.path()); + if (filePath.startsWith(QLatin1Char('/'))) + filePath = filePath.mid(1); + QString virtualFolder = filePath.mid(0, filePath.indexOf(QLatin1Char('/'), 1)); + filePath = filePath.mid(virtualFolder.length()+1); + + QHelpDBReader *defaultReader = 0; + if (d->readerMap.contains(ns)) { + defaultReader = d->readerMap.value(ns); + if (defaultReader->fileExists(virtualFolder, filePath)) + return url; + } + + QStringList filterAtts = filterAttributes(currentFilter()); + foreach (QHelpDBReader *reader, d->virtualFolderMap.values(virtualFolder)) { + if (reader == defaultReader) + continue; + if (reader->fileExists(virtualFolder, filePath, filterAtts)) { + res = url; + res.setAuthority(reader->namespaceName()); + return res; + } + } + + foreach (QHelpDBReader *reader, d->virtualFolderMap.values(virtualFolder)) { + if (reader == defaultReader) + continue; + if (reader->fileExists(virtualFolder, filePath)) { + res = url; + res.setAuthority(reader->namespaceName()); + break; + } + } + + return res; +} + +/*! + Returns the data of the file specified by \a url. If the + file does not exist, an empty QByteArray is returned. + + \sa findFile() +*/ +QByteArray QHelpEngineCore::fileData(const QUrl &url) const +{ + if (!d->setup() || !url.isValid() || url.toString().count(QLatin1Char('/')) < 4 + || url.scheme() != QLatin1String("qthelp")) + return QByteArray(); + + QString ns = url.authority(); + QString filePath = QDir::cleanPath(url.path()); + if (filePath.startsWith(QLatin1Char('/'))) + filePath = filePath.mid(1); + QString virtualFolder = filePath.mid(0, filePath.indexOf(QLatin1Char('/'), 1)); + filePath = filePath.mid(virtualFolder.length()+1); + + QByteArray ba; + QHelpDBReader *defaultReader = 0; + if (d->readerMap.contains(ns)) { + defaultReader = d->readerMap.value(ns); + ba = defaultReader->fileData(virtualFolder, filePath); + } + + if (ba.isEmpty()) { + foreach (QHelpDBReader *reader, d->virtualFolderMap.values(virtualFolder)) { + if (reader == defaultReader) + continue; + ba = reader->fileData(virtualFolder, filePath); + if (!ba.isEmpty()) + return ba; + } + } + return ba; +} + +/*! + Returns a map of hits found for the \a id. A hit contains the + title of the document and the url where the keyword is located. + The result depends on the current filter, meaning only the keywords + registered for the current filter will be returned. +*/ +QMap<QString, QUrl> QHelpEngineCore::linksForIdentifier(const QString &id) const +{ + QMap<QString, QUrl> linkMap; + if (!d->setup()) + return linkMap; + + QStringList atts = filterAttributes(d->currentFilter); + foreach (QHelpDBReader *reader, d->readerMap) + reader->linksForIdentifier(id, atts, linkMap); + + return linkMap; +} + +/*! + Removes the \a key from the settings section in the + collection file. Returns true if the value was removed + successfully, otherwise false. + + \sa customValue(), setCustomValue() +*/ +bool QHelpEngineCore::removeCustomValue(const QString &key) +{ + d->error.clear(); + return d->collectionHandler->removeCustomValue(key); +} + +/*! + Returns the value assigned to the \a key. If the requested + key does not exist, the specified \a defaultValue is + returned. + + \sa setCustomValue(), removeCustomValue() +*/ +QVariant QHelpEngineCore::customValue(const QString &key, const QVariant &defaultValue) const +{ + if (!d->setup()) + return QVariant(); + return d->collectionHandler->customValue(key, defaultValue); +} + +/*! + Save the \a value under the \a key. If the key already exist, + the value will be overwritten. Returns true if the value was + saved successfully, otherwise false. + + \sa customValue(), removeCustomValue() +*/ +bool QHelpEngineCore::setCustomValue(const QString &key, const QVariant &value) +{ + d->error.clear(); + return d->collectionHandler->setCustomValue(key, value); +} + +/*! + Returns the meta data for the Qt compressed help file \a + documentationFileName. If there is no data available for + \a name, an invalid QVariant() is returned. The meta + data is defined when creating the Qt compressed help file and + cannot be modified later. Common meta data includes e.g. + the author of the documentation. +*/ +QVariant QHelpEngineCore::metaData(const QString &documentationFileName, + const QString &name) +{ + QHelpDBReader reader(documentationFileName, QLatin1String("GetMetaData"), 0); + + if (reader.init()) + return reader.metaData(name); + return QVariant(); +} + +/*! + Returns a description of the last error that occured. +*/ +QString QHelpEngineCore::error() const +{ + return d->error; +} + +/*! + \property QHelpEngineCore::autoSaveFilter + \brief whether QHelpEngineCore is in auto save filter mode or not. + \since 4.5 + + If QHelpEngineCore is in auto save filter mode, the current filter is + automatically saved when it is changed by the setCurrentFilter() + function. The filter is saved persistently in the help collection file. + + By default, this mode is on. +*/ +void QHelpEngineCore::setAutoSaveFilter(bool save) +{ + d->autoSaveFilter = save; +} + +bool QHelpEngineCore::autoSaveFilter() const +{ + return d->autoSaveFilter; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpenginecore.h b/tools/assistant/lib/qhelpenginecore.h new file mode 100644 index 0000000..92ba2fd --- /dev/null +++ b/tools/assistant/lib/qhelpenginecore.h @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPENGINECORE_H +#define QHELPENGINECORE_H + +#include <QtHelp/qhelp_global.h> + +#include <QtCore/QUrl> +#include <QtCore/QMap> +#include <QtCore/QObject> +#include <QtCore/QVariant> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Help) + +class QHelpEngineCorePrivate; + +class QHELP_EXPORT QHelpEngineCore : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool autoSaveFilter READ autoSaveFilter WRITE setAutoSaveFilter) + Q_PROPERTY(QString collectionFile READ collectionFile WRITE setCollectionFile) + Q_PROPERTY(QString currentFilter READ currentFilter WRITE setCurrentFilter) + +public: + QHelpEngineCore(const QString &collectionFile, QObject *parent = 0); + virtual ~QHelpEngineCore(); + + bool setupData(); + + QString collectionFile() const; + void setCollectionFile(const QString &fileName); + + bool copyCollectionFile(const QString &fileName); + + static QString namespaceName(const QString &documentationFileName); + bool registerDocumentation(const QString &documentationFileName); + bool unregisterDocumentation(const QString &namespaceName); + QString documentationFileName(const QString &namespaceName); + + QStringList customFilters() const; + bool removeCustomFilter(const QString &filterName); + bool addCustomFilter(const QString &filterName, + const QStringList &attributes); + + QStringList filterAttributes() const; + QStringList filterAttributes(const QString &filterName) const; + + QString currentFilter() const; + void setCurrentFilter(const QString &filterName); + + QStringList registeredDocumentations() const; + QList<QStringList> filterAttributeSets(const QString &namespaceName) const; + QList<QUrl> files(const QString namespaceName, + const QStringList &filterAttributes, + const QString &extensionFilter = QString()); + QUrl findFile(const QUrl &url) const; + QByteArray fileData(const QUrl &url) const; + + QMap<QString, QUrl> linksForIdentifier(const QString &id) const; + + bool removeCustomValue(const QString &key); + QVariant customValue(const QString &key, + const QVariant &defaultValue = QVariant()) const; + bool setCustomValue(const QString &key, const QVariant &value); + + static QVariant metaData(const QString &documentationFileName, + const QString &name); + + QString error() const; + + void setAutoSaveFilter(bool save); + bool autoSaveFilter() const; + +Q_SIGNALS: + void setupStarted(); + void setupFinished(); + void currentFilterChanged(const QString &newFilter); + void warning(const QString &msg); + +protected: + QHelpEngineCore(QHelpEngineCorePrivate *helpEngineCorePrivate, + QObject *parent); + +private: + QHelpEngineCorePrivate *d; + friend class QHelpEngineCorePrivate; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QHELPENGINECORE_H diff --git a/tools/assistant/lib/qhelpgenerator.cpp b/tools/assistant/lib/qhelpgenerator.cpp new file mode 100644 index 0000000..03df3cc --- /dev/null +++ b/tools/assistant/lib/qhelpgenerator.cpp @@ -0,0 +1,823 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpgenerator_p.h" +#include "qhelpdatainterface_p.h" + +#include <math.h> +#include <QtCore/QFile> +#include <QtCore/QFileInfo> +#include <QtCore/QDir> +#include <QtCore/QDebug> +#include <QtCore/QVariant> +#include <QtCore/QDateTime> +#include <QtCore/QTextCodec> +#include <QtSql/QSqlQuery> + +QT_BEGIN_NAMESPACE + +class QHelpGeneratorPrivate +{ +public: + QHelpGeneratorPrivate(); + ~QHelpGeneratorPrivate(); + + QString error; + QSqlQuery *query; + + int namespaceId; + int virtualFolderId; + + QMap<QString, int> fileMap; + QMap<int, QSet<int> > fileFilterMap; + + double progress; + double oldProgress; + double contentStep; + double fileStep; + double indexStep; +}; + +QHelpGeneratorPrivate::QHelpGeneratorPrivate() +{ + query = 0; + namespaceId = -1; + virtualFolderId = -1; +} + +QHelpGeneratorPrivate::~QHelpGeneratorPrivate() +{ +} + + + +/*! + \internal + \class QHelpGenerator + \since 4.4 + \brief The QHelpGenerator class generates a new + Qt compressed help file (.qch). + + The help generator takes a help data structure as + input for generating a new Qt compressed help files. Since + the generation may takes some time, the generator emits + various signals to inform about its current state. +*/ + +/*! + \fn void QHelpGenerator::statusChanged(const QString &msg) + + This signal is emitted when the generation status changes. + The status is basically a specific task like inserting + files or building up the keyword index. The parameter + \a msg contains the detailed status description. +*/ + +/*! + \fn void QHelpGenerator::progressChanged(double progress) + + This signal is emitted when the progress changes. The + \a progress ranges from 0 to 100. +*/ + +/*! + \fn void QHelpGenerator::warning(const QString &msg) + + This signal is emitted when a non critical error occurs, + e.g. when a referenced file cannot be found. \a msg + contains the exact warning message. +*/ + +/*! + Constructs a new help generator with the give \a parent. +*/ +QHelpGenerator::QHelpGenerator(QObject *parent) + : QObject(parent) +{ + d = new QHelpGeneratorPrivate; +} + +/*! + Destructs the help generator. +*/ +QHelpGenerator::~QHelpGenerator() +{ + delete d; +} + +/*! + Takes the \a helpData and generates a new documentation + set from it. The Qt compressed help file is written to \a + outputFileName. Returns true on success, otherwise false. +*/ +bool QHelpGenerator::generate(QHelpDataInterface *helpData, + const QString &outputFileName) +{ + emit progressChanged(0); + d->error.clear(); + if (!helpData || helpData->namespaceName().isEmpty()) { + d->error = tr("Invalid help data!"); + return false; + } + + QString outFileName = outputFileName; + if (outFileName.isEmpty()) { + d->error = tr("No output file name specified!"); + return false; + } + + QFileInfo fi(outFileName); + if (fi.exists()) { + if (!fi.dir().remove(fi.fileName())) { + d->error = tr("The file %1 cannot be overwritten!").arg(outFileName); + return false; + } + } + + setupProgress(helpData); + + emit statusChanged(tr("Building up file structure...")); + bool openingOk = true; + { + QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), QLatin1String("builder")); + db.setDatabaseName(outFileName); + openingOk = db.open(); + if (openingOk) + d->query = new QSqlQuery(db); + } + + if (!openingOk) { + d->error = tr("Cannot open data base file %1!").arg(outFileName); + cleanupDB(); + return false; + } + + addProgress(1.0); + createTables(); + insertFileNotFoundFile(); + insertMetaData(helpData->metaData()); + + if (!registerVirtualFolder(helpData->virtualFolder(), helpData->namespaceName())) { + d->error = tr("Cannot register namespace %1!").arg(helpData->namespaceName()); + cleanupDB(); + return false; + } + addProgress(1.0); + + emit statusChanged(tr("Insert custom filters...")); + foreach (QHelpDataCustomFilter f, helpData->customFilters()) { + if (!registerCustomFilter(f.name, f.filterAttributes, true)) { + cleanupDB(); + return false; + } + } + addProgress(1.0); + + int i = 1; + QList<QHelpDataFilterSection>::const_iterator it = helpData->filterSections().constBegin(); + while (it != helpData->filterSections().constEnd()) { + emit statusChanged(tr("Insert help data for filter section (%1 of %2)...") + .arg(i++).arg(helpData->filterSections().count())); + insertFilterAttributes((*it).filterAttributes()); + QByteArray ba; + QDataStream s(&ba, QIODevice::WriteOnly); + foreach (QHelpDataContentItem *itm, (*it).contents()) + writeTree(s, itm, 0); + if (!insertFiles((*it).files(), helpData->rootPath(), (*it).filterAttributes()) + || !insertContents(ba, (*it).filterAttributes()) + || !insertKeywords((*it).indices(), (*it).filterAttributes())) { + cleanupDB(); + return false; + } + ++it; + } + + cleanupDB(); + emit progressChanged(100); + emit statusChanged(tr("Documentation successfully generated.")); + return true; +} + +void QHelpGenerator::setupProgress(QHelpDataInterface *helpData) +{ + d->progress = 0; + d->oldProgress = 0; + + int numberOfFiles = 0; + int numberOfIndices = 0; + QList<QHelpDataFilterSection>::const_iterator it = helpData->filterSections().constBegin(); + while (it != helpData->filterSections().constEnd()) { + numberOfFiles += (*it).files().count(); + numberOfIndices += (*it).indices().count(); + ++it; + } + // init 2% + // filters 1% + // contents 10% + // files 60% + // indices 27% + d->contentStep = 10.0/(double)helpData->customFilters().count(); + d->fileStep = 60.0/(double)numberOfFiles; + d->indexStep = 27.0/(double)numberOfIndices; +} + +void QHelpGenerator::addProgress(double step) +{ + d->progress += step; + if ((d->progress-d->oldProgress) >= 1.0 && d->progress <= 100.0) { + d->oldProgress = d->progress; + emit progressChanged(ceil(d->progress)); + } +} + +void QHelpGenerator::cleanupDB() +{ + if (d->query) { + d->query->clear(); + delete d->query; + d->query = 0; + } + QSqlDatabase::removeDatabase(QLatin1String("builder")); +} + +void QHelpGenerator::writeTree(QDataStream &s, QHelpDataContentItem *item, int depth) +{ + QString fReference = QDir::cleanPath(item->reference()); + if (fReference.startsWith(QLatin1String("./"))) + fReference = fReference.mid(2); + + s << depth; + s << fReference; + s << item->title(); + foreach (QHelpDataContentItem *i, item->children()) + writeTree(s, i, depth+1); +} + +/*! + Returns the last error message. +*/ +QString QHelpGenerator::error() const +{ + return d->error; +} + +bool QHelpGenerator::createTables() +{ + if (!d->query) + return false; + + d->query->exec(QLatin1String("SELECT COUNT(*) FROM sqlite_master WHERE TYPE=\'table\'" + "AND Name=\'NamespaceTable\'")); + d->query->next(); + if (d->query->value(0).toInt() > 0) { + d->error = tr("Some tables already exist!"); + return false; + } + + QStringList tables; + tables << QLatin1String("CREATE TABLE NamespaceTable (" + "Id INTEGER PRIMARY KEY," + "Name TEXT )") + << QLatin1String("CREATE TABLE FilterAttributeTable (" + "Id INTEGER PRIMARY KEY, " + "Name TEXT )") + << QLatin1String("CREATE TABLE FilterNameTable (" + "Id INTEGER PRIMARY KEY, " + "Name TEXT )") + << QLatin1String("CREATE TABLE FilterTable (" + "NameId INTEGER, " + "FilterAttributeId INTEGER )") + << QLatin1String("CREATE TABLE IndexTable (" + "Id INTEGER PRIMARY KEY, " + "Name TEXT, " + "Identifier TEXT, " + "NamespaceId INTEGER, " + "FileId INTEGER, " + "Anchor TEXT )") + << QLatin1String("CREATE TABLE IndexItemTable (" + "Id INTEGER, " + "IndexId INTEGER )") + << QLatin1String("CREATE TABLE IndexFilterTable (" + "FilterAttributeId INTEGER, " + "IndexId INTEGER )") + << QLatin1String("CREATE TABLE ContentsTable (" + "Id INTEGER PRIMARY KEY, " + "NamespaceId INTEGER, " + "Data BLOB )") + << QLatin1String("CREATE TABLE ContentsFilterTable (" + "FilterAttributeId INTEGER, " + "ContentsId INTEGER )") + << QLatin1String("CREATE TABLE FileAttributeSetTable (" + "Id INTEGER, " + "FilterAttributeId INTEGER )") + << QLatin1String("CREATE TABLE FileDataTable (" + "Id INTEGER PRIMARY KEY, " + "Data BLOB )") + << QLatin1String("CREATE TABLE FileFilterTable (" + "FilterAttributeId INTEGER, " + "FileId INTEGER )") + << QLatin1String("CREATE TABLE FileNameTable (" + "FolderId INTEGER, " + "Name TEXT, " + "FileId INTEGER, " + "Title TEXT )") + << QLatin1String("CREATE TABLE FolderTable(" + "Id INTEGER PRIMARY KEY, " + "Name Text, " + "NamespaceID INTEGER )") + << QLatin1String("CREATE TABLE MetaDataTable(" + "Name Text, " + "Value BLOB )"); + + foreach (QString q, tables) { + if (!d->query->exec(q)) { + d->error = tr("Cannot create tables!"); + return false; + } + } + + d->query->exec(QLatin1String("INSERT INTO MetaDataTable VALUES('qchVersion', '1.0')")); + + d->query->prepare(QLatin1String("INSERT INTO MetaDataTable VALUES('CreationDate', ?)")); + d->query->bindValue(0, QDateTime::currentDateTime().toString(Qt::ISODate)); + d->query->exec(); + + return true; +} + +bool QHelpGenerator::insertFileNotFoundFile() +{ + if (!d->query) + return false; + + d->query->exec(QLatin1String("SELECT id FROM FileNameTable WHERE Name=\'\'")); + if (d->query->next() && d->query->isValid()) + return true; + + d->query->prepare(QLatin1String("INSERT INTO FileDataTable VALUES (Null, ?)")); + d->query->bindValue(0, QByteArray()); + if (!d->query->exec()) + return false; + + int fileId = d->query->lastInsertId().toInt(); + d->query->prepare(QLatin1String("INSERT INTO FileNameTable (FolderId, Name, FileId, Title) " + " VALUES (0, '', ?, '')")); + d->query->bindValue(0, fileId); + if (fileId > -1 && d->query->exec()) { + d->fileMap.insert(QString(), fileId); + return true; + } + return false; +} + +bool QHelpGenerator::registerVirtualFolder(const QString &folderName, const QString &ns) +{ + if (!d->query || folderName.isEmpty() || ns.isEmpty()) + return false; + + d->query->prepare(QLatin1String("SELECT Id FROM FolderTable WHERE Name=?")); + d->query->bindValue(0, folderName); + d->query->exec(); + d->query->next(); + if (d->query->isValid() && d->query->value(0).toInt() > 0) + return true; + + d->namespaceId = -1; + d->query->prepare(QLatin1String("SELECT Id FROM NamespaceTable WHERE Name=?")); + d->query->bindValue(0, ns); + d->query->exec(); + while (d->query->next()) { + d->namespaceId = d->query->value(0).toInt(); + break; + } + + if (d->namespaceId < 0) { + d->query->prepare(QLatin1String("INSERT INTO NamespaceTable VALUES(NULL, ?)")); + d->query->bindValue(0, ns); + if (d->query->exec()) + d->namespaceId = d->query->lastInsertId().toInt(); + } + + if (d->namespaceId > 0) { + d->query->prepare(QLatin1String("SELECT Id FROM FolderTable WHERE Name=?")); + d->query->bindValue(0, folderName); + d->query->exec(); + while (d->query->next()) + d->virtualFolderId = d->query->value(0).toInt(); + + if (d->virtualFolderId > 0) + return true; + + d->query->prepare(QLatin1String("INSERT INTO FolderTable (NamespaceId, Name) " + "VALUES (?, ?)")); + d->query->bindValue(0, d->namespaceId); + d->query->bindValue(1, folderName); + if (d->query->exec()) { + d->virtualFolderId = d->query->lastInsertId().toInt(); + return d->virtualFolderId > 0; + } + } + d->error = tr("Cannot register virtual folder!"); + return false; +} + +bool QHelpGenerator::insertFiles(const QStringList &files, const QString &rootPath, + const QStringList &filterAttributes) +{ + if (!d->query) + return false; + + emit statusChanged(tr("Insert files...")); + QList<int> filterAtts; + foreach (QString filterAtt, filterAttributes) { + d->query->prepare(QLatin1String("SELECT Id FROM FilterAttributeTable WHERE Name=?")); + d->query->bindValue(0, filterAtt); + d->query->exec(); + if (d->query->next()) + filterAtts.append(d->query->value(0).toInt()); + } + + int filterSetId = -1; + d->query->exec(QLatin1String("SELECT MAX(Id) FROM FileAttributeSetTable")); + if (d->query->next()) + filterSetId = d->query->value(0).toInt(); + if (filterSetId < 0) + return false; + ++filterSetId; + foreach (int attId, filterAtts) { + d->query->prepare(QLatin1String("INSERT INTO FileAttributeSetTable VALUES(?, ?)")); + d->query->bindValue(0, filterSetId); + d->query->bindValue(1, attId); + d->query->exec(); + } + + QString title; + QString charSet; + QMap<int, QSet<int> > tmpFileFilterMap; + QList<FileNameTableData> fileNameDataList; + QList<QByteArray> fileDataList; + + int tableFileId = 1; + d->query->exec(QLatin1String("SELECT MAX(Id) FROM FileDataTable")); + if (d->query->next()) + tableFileId = d->query->value(0).toInt() + 1; + + FileNameTableData fileNameData; + + int i = 0; + foreach (QString file, files) { + QFileInfo fi(rootPath + QDir::separator() + file); + if (!fi.exists()) { + emit warning(tr("The file %1 does not exist! Skipping it.") + .arg(fi.absoluteFilePath())); + continue; + } + + QFile f(fi.absoluteFilePath()); + if (!f.open(QIODevice::ReadOnly)) { + emit warning(tr("Cannot open file %1! Skipping it.") + .arg(fi.absoluteFilePath())); + continue; + } + + title.clear(); + QByteArray data; + data = f.readAll(); + + if (fi.suffix() == QLatin1String("html") || fi.suffix() == QLatin1String("htm")) { + charSet = QHelpGlobal::charsetFromData(data); + QTextStream stream(&data); + stream.setCodec(QTextCodec::codecForName(charSet.toLatin1().constData())); + title = QHelpGlobal::documentTitle(stream.readAll()); + } else { + title = fi.fileName(); + } + + QString fName = QDir::cleanPath(file); + if (fName.startsWith(QLatin1String("./"))) + fName = fName.mid(2); + + int fileId = -1; + if (!d->fileMap.contains(fName)) { + fileDataList.append(qCompress(data)); + + fileNameData.name = fName; + fileNameData.fileId = tableFileId; + fileNameData.title = title; + fileNameDataList.append(fileNameData); + + d->fileMap.insert(fName, tableFileId); + d->fileFilterMap.insert(tableFileId, filterAtts.toSet()); + tmpFileFilterMap.insert(tableFileId, filterAtts.toSet()); + + ++tableFileId; + } else { + fileId = d->fileMap.value(fName); + foreach (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 (tmpFileFilterMap.count()) { + d->query->exec(QLatin1String("BEGIN")); + QMap<int, QSet<int> >::const_iterator it = tmpFileFilterMap.constBegin(); + while (it != tmpFileFilterMap.constEnd()) { + QSet<int>::const_iterator i = it.value().constBegin(); + while (i != it.value().constEnd()) { + d->query->prepare(QLatin1String("INSERT INTO FileFilterTable VALUES(?, ?)")); + d->query->bindValue(0, *i); + d->query->bindValue(1, it.key()); + d->query->exec(); + ++i; + } + ++it; + } + + QList<QByteArray>::const_iterator fileIt = fileDataList.constBegin(); + while (fileIt != fileDataList.constEnd()) { + d->query->prepare(QLatin1String("INSERT INTO FileDataTable VALUES (Null, ?)")); + d->query->bindValue(0, *fileIt); + d->query->exec(); + ++fileIt; + if (++i%20 == 0) + addProgress(d->fileStep*20.0); + } + + QList<FileNameTableData>::const_iterator fileNameIt = fileNameDataList.constBegin(); + while (fileNameIt != fileNameDataList.constEnd()) { + d->query->prepare(QLatin1String("INSERT INTO FileNameTable (FolderId, Name, FileId, Title) " + " VALUES (?, ?, ?, ?)")); + d->query->bindValue(0, 1); + d->query->bindValue(1, (*fileNameIt).name); + d->query->bindValue(2, (*fileNameIt).fileId); + d->query->bindValue(3, (*fileNameIt).title); + d->query->exec(); + ++fileNameIt; + } + d->query->exec(QLatin1String("COMMIT")); + } + + d->query->exec(QLatin1String("SELECT MAX(Id) FROM FileDataTable")); + if (d->query->next() + && d->query->value(0).toInt() == tableFileId-1) { + addProgress(d->fileStep*(i%20)); + return true; + } + return false; +} + +bool QHelpGenerator::registerCustomFilter(const QString &filterName, const QStringList &filterAttribs, + bool forceUpdate) +{ + if (!d->query) + return false; + + d->query->exec(QLatin1String("SELECT Id, Name FROM FilterAttributeTable")); + QStringList idsToInsert = filterAttribs; + QMap<QString, int> attributeMap; + 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()); + } + + foreach (QString id, idsToInsert) { + d->query->prepare(QLatin1String("INSERT INTO FilterAttributeTable VALUES(NULL, ?)")); + d->query->bindValue(0, id); + d->query->exec(); + attributeMap.insert(id, d->query->lastInsertId().toInt()); + } + + int nameId = -1; + d->query->prepare(QLatin1String("SELECT Id FROM FilterNameTable WHERE Name=?")); + d->query->bindValue(0, filterName); + d->query->exec(); + while (d->query->next()) { + nameId = d->query->value(0).toInt(); + break; + } + + if (nameId < 0) { + d->query->prepare(QLatin1String("INSERT INTO FilterNameTable VALUES(NULL, ?)")); + d->query->bindValue(0, filterName); + if (d->query->exec()) + nameId = d->query->lastInsertId().toInt(); + } else if (!forceUpdate) { + d->error = tr("The filter %1 is already registered!").arg(filterName); + return false; + } + + if (nameId < 0) { + d->error = tr("Cannot register filter %1!").arg(filterName); + return false; + } + + d->query->prepare(QLatin1String("DELETE FROM FilterTable WHERE NameId=?")); + d->query->bindValue(0, nameId); + d->query->exec(); + + foreach (QString att, filterAttribs) { + d->query->prepare(QLatin1String("INSERT INTO FilterTable VALUES(?, ?)")); + d->query->bindValue(0, nameId); + d->query->bindValue(1, attributeMap[att]); + if (!d->query->exec()) + return false; + } + return true; +} + +bool QHelpGenerator::insertKeywords(const QList<QHelpDataIndexItem> keywords, + const QStringList &filterAttributes) +{ + if (!d->query) + return false; + + emit statusChanged(tr("Insert indices...")); + int indexId = 1; + d->query->exec(QLatin1String("SELECT MAX(Id) FROM IndexTable")); + if (d->query->next()) + indexId = d->query->value(0).toInt() + 1; + + QList<int> filterAtts; + foreach (QString filterAtt, filterAttributes) { + d->query->prepare(QLatin1String("SELECT Id FROM FilterAttributeTable WHERE Name=?")); + d->query->bindValue(0, filterAtt); + d->query->exec(); + if (d->query->next()) + filterAtts.append(d->query->value(0).toInt()); + } + + int pos = -1; + QString fileName; + QString anchor; + QString fName; + int fileId = 1; + QList<int> indexFilterTable; + + int i = 0; + d->query->exec(QLatin1String("BEGIN")); + foreach (QHelpDataIndexItem itm, keywords) { + pos = itm.reference.indexOf(QLatin1Char('#')); + fileName = itm.reference.left(pos); + if (pos > -1) + anchor = itm.reference.mid(pos+1); + else + anchor.clear(); + + fName = QDir::cleanPath(fileName); + if (fName.startsWith(QLatin1String("./"))) + fName = fName.mid(2); + + if (d->fileMap.contains(fName)) + fileId = d->fileMap.value(fName); + else + fileId = 1; + + d->query->prepare(QLatin1String("INSERT INTO IndexTable (Name, Identifier, NamespaceId, FileId, Anchor) " + "VALUES(?, ?, ?, ?, ?)")); + d->query->bindValue(0, itm.name); + d->query->bindValue(1, itm.identifier); + d->query->bindValue(2, d->namespaceId); + d->query->bindValue(3, fileId); + d->query->bindValue(4, anchor); + d->query->exec(); + + indexFilterTable.append(indexId++); + if (++i%100 == 0) + addProgress(d->indexStep*100.0); + } + d->query->exec(QLatin1String("COMMIT")); + + d->query->exec(QLatin1String("BEGIN")); + foreach (int idx, indexFilterTable) { + foreach (int a, filterAtts) { + d->query->prepare(QLatin1String("INSERT INTO IndexFilterTable (FilterAttributeId, IndexId) " + "VALUES(?, ?)")); + d->query->bindValue(0, a); + d->query->bindValue(1, idx); + d->query->exec(); + } + } + 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()) + return true; + return false; +} + +bool QHelpGenerator::insertContents(const QByteArray &ba, + const QStringList &filterAttributes) +{ + if (!d->query) + return false; + + emit statusChanged(tr("Insert contents...")); + d->query->prepare(QLatin1String("INSERT INTO ContentsTable (NamespaceId, Data) " + "VALUES(?, ?)")); + d->query->bindValue(0, d->namespaceId); + d->query->bindValue(1, ba); + d->query->exec(); + int contentId = d->query->lastInsertId().toInt(); + if (contentId < 1) { + d->error = tr("Cannot insert contents!"); + return false; + } + + // associate the filter attributes + foreach (QString filterAtt, filterAttributes) { + d->query->prepare(QLatin1String("INSERT INTO ContentsFilterTable (FilterAttributeId, ContentsId) " + "SELECT Id, ? FROM FilterAttributeTable WHERE Name=?")); + d->query->bindValue(0, contentId); + d->query->bindValue(1, filterAtt); + d->query->exec(); + if (!d->query->isActive()) { + d->error = tr("Cannot register contents!"); + return false; + } + } + addProgress(d->contentStep); + return true; +} + +bool QHelpGenerator::insertFilterAttributes(const QStringList &attributes) +{ + if (!d->query) + return false; + + d->query->exec(QLatin1String("SELECT Name FROM FilterAttributeTable")); + QSet<QString> atts; + while (d->query->next()) + atts.insert(d->query->value(0).toString()); + + foreach (QString s, attributes) { + if (!atts.contains(s)) { + d->query->prepare(QLatin1String("INSERT INTO FilterAttributeTable VALUES(NULL, ?)")); + d->query->bindValue(0, s); + d->query->exec(); + } + } + return true; +} + +bool QHelpGenerator::insertMetaData(const QMap<QString, QVariant> &metaData) +{ + if (!d->query) + return false; + + QMap<QString, QVariant>::const_iterator it = metaData.constBegin(); + while (it != metaData.constEnd()) { + d->query->prepare(QLatin1String("INSERT INTO MetaDataTable VALUES(?, ?)")); + d->query->bindValue(0, it.key()); + d->query->bindValue(1, it.value()); + d->query->exec(); + ++it; + } + return true; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpgenerator_p.h b/tools/assistant/lib/qhelpgenerator_p.h new file mode 100644 index 0000000..ddf2aed --- /dev/null +++ b/tools/assistant/lib/qhelpgenerator_p.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPGENERATOR_H +#define QHELPGENERATOR_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhelp_global.h" +#include "qhelpdatainterface_p.h" + +#include <QtCore/QObject> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QHelpGeneratorPrivate; + +class QHELP_EXPORT QHelpGenerator : public QObject +{ + Q_OBJECT + +public: + QHelpGenerator(QObject *parent = 0); + ~QHelpGenerator(); + + bool generate(QHelpDataInterface *helpData, + const QString &outputFileName); + QString error() const; + +Q_SIGNALS: + void statusChanged(const QString &msg); + void progressChanged(double progress); + void warning(const QString &msg); + +private: + struct FileNameTableData + { + QString name; + int fileId; + QString title; + }; + + void writeTree(QDataStream &s, QHelpDataContentItem *item, int depth); + bool createTables(); + bool insertFileNotFoundFile(); + bool registerCustomFilter(const QString &filterName, + 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, + const QStringList &filterAttributes); + bool insertFiles(const QStringList &files, const QString &rootPath, + const QStringList &filterAttributes); + bool insertContents(const QByteArray &ba, + const QStringList &filterAttributes); + bool insertMetaData(const QMap<QString, QVariant> &metaData); + void cleanupDB(); + void setupProgress(QHelpDataInterface *helpData); + void addProgress(double step); + + QHelpGeneratorPrivate *d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/tools/assistant/lib/qhelpindexwidget.cpp b/tools/assistant/lib/qhelpindexwidget.cpp new file mode 100644 index 0000000..7db9867 --- /dev/null +++ b/tools/assistant/lib/qhelpindexwidget.cpp @@ -0,0 +1,445 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpindexwidget.h" +#include "qhelpenginecore.h" +#include "qhelpengine_p.h" +#include "qhelpdbreader_p.h" + +#include <QtCore/QThread> +#include <QtCore/QMutex> +#include <QtGui/QListView> +#include <QtGui/QHeaderView> + +QT_BEGIN_NAMESPACE + +class QHelpIndexProvider : public QThread +{ +public: + QHelpIndexProvider(QHelpEnginePrivate *helpEngine); + ~QHelpIndexProvider(); + void collectIndices(const QString &customFilterName); + void stopCollecting(); + QStringList indices() const; + QList<QHelpDBReader*> activeReaders() const; + QSet<int> indexIds(QHelpDBReader *reader) const; + +private: + void run(); + + QHelpEnginePrivate *m_helpEngine; + QStringList m_indices; + QList<QHelpDBReader*> m_activeReaders; + QMap<QHelpDBReader*, QSet<int> > m_indexIds; + QStringList m_filterAttributes; + mutable QMutex m_mutex; + bool m_abort; +}; + +class QHelpIndexModelPrivate +{ +public: + QHelpIndexModelPrivate(QHelpEnginePrivate *hE) + { + helpEngine = hE; + indexProvider = new QHelpIndexProvider(helpEngine); + insertedRows = 0; + } + + QHelpEnginePrivate *helpEngine; + QHelpIndexProvider *indexProvider; + QStringList indices; + int insertedRows; + QString currentFilter; + QList<QHelpDBReader*> activeReaders; +}; + +static bool caseInsensitiveLessThan(const QString &as, const QString &bs) +{ + return QString::compare(as, bs, Qt::CaseInsensitive) < 0; +} + +QHelpIndexProvider::QHelpIndexProvider(QHelpEnginePrivate *helpEngine) + : QThread(helpEngine) +{ + m_helpEngine = helpEngine; + m_abort = false; +} + +QHelpIndexProvider::~QHelpIndexProvider() +{ + stopCollecting(); +} + +void QHelpIndexProvider::collectIndices(const QString &customFilterName) +{ + m_mutex.lock(); + m_filterAttributes = m_helpEngine->q->filterAttributes(customFilterName); + m_mutex.unlock(); + if (!isRunning()) { + start(LowPriority); + } else { + stopCollecting(); + start(LowPriority); + } +} + +void QHelpIndexProvider::stopCollecting() +{ + if (!isRunning()) + return; + m_mutex.lock(); + m_abort = true; + m_mutex.unlock(); + wait(); +} + +QStringList QHelpIndexProvider::indices() const +{ + QMutexLocker lck(&m_mutex); + return m_indices; +} + +QList<QHelpDBReader*> QHelpIndexProvider::activeReaders() const +{ + QMutexLocker lck(&m_mutex); + return m_activeReaders; +} + +QSet<int> QHelpIndexProvider::indexIds(QHelpDBReader *reader) const +{ + QMutexLocker lck(&m_mutex); + if (m_indexIds.contains(reader)) + return m_indexIds.value(reader); + return QSet<int>(); +} + +void QHelpIndexProvider::run() +{ + m_mutex.lock(); + QStringList atts = m_filterAttributes; + m_indices.clear(); + m_activeReaders.clear(); + QSet<QString> indicesSet; + m_mutex.unlock(); + + foreach (QString dbFileName, m_helpEngine->fileNameReaderMap.keys()) { + m_mutex.lock(); + if (m_abort) { + m_abort = false; + m_mutex.unlock(); + return; + } + m_mutex.unlock(); + QHelpDBReader reader(dbFileName, + QHelpGlobal::uniquifyConnectionName(dbFileName + + QLatin1String("FromIndexProvider"), + QThread::currentThread()), 0); + if (!reader.init()) + continue; + QStringList lst = reader.indicesForFilter(atts); + if (!lst.isEmpty()) { + m_mutex.lock(); + foreach (QString s, lst) + indicesSet.insert(s); + if (m_abort) { + m_abort = false; + m_mutex.unlock(); + return; + } + QHelpDBReader *orgReader = m_helpEngine->fileNameReaderMap.value(dbFileName); + m_indexIds.insert(orgReader, reader.indexIds(atts)); + m_activeReaders.append(orgReader); + m_mutex.unlock(); + } + } + m_mutex.lock(); + m_indices = indicesSet.values(); + qSort(m_indices.begin(), m_indices.end(), caseInsensitiveLessThan); + m_abort = false; + m_mutex.unlock(); +} + + + +/*! + \class QHelpIndexModel + \since 4.4 + \inmodule QtHelp + \brief The QHelpIndexModel class provides a model that + supplies index keywords to views. + + +*/ + +/*! + \fn void QHelpIndexModel::indexCreationStarted() + + This signal is emitted when the creation of a new index + has started. The current index is invalid from this + point on until the signal indexCreated() is emitted. + + \sa isCreatingIndex() +*/ + +/*! + \fn void QHelpIndexModel::indexCreated() + + This signal is emitted when the index has been created. +*/ + +QHelpIndexModel::QHelpIndexModel(QHelpEnginePrivate *helpEngine) + : QStringListModel(helpEngine) +{ + d = new QHelpIndexModelPrivate(helpEngine); + + connect(d->indexProvider, SIGNAL(finished()), this, SLOT(insertIndices())); + connect(helpEngine->q, SIGNAL(setupStarted()), this, SLOT(invalidateIndex())); +} + +QHelpIndexModel::~QHelpIndexModel() +{ + delete d; +} + +void QHelpIndexModel::invalidateIndex(bool onShutDown) +{ + if (onShutDown) + disconnect(this, SLOT(insertIndices())); + d->indexProvider->stopCollecting(); + d->indices.clear(); + filter(QString()); +} + +/*! + Creates a new index by querying the help system for + keywords for the specified \a customFilterName. +*/ +void QHelpIndexModel::createIndex(const QString &customFilterName) +{ + d->currentFilter = customFilterName; + d->indexProvider->collectIndices(customFilterName); + emit indexCreationStarted(); +} + +void QHelpIndexModel::insertIndices() +{ + d->indices = d->indexProvider->indices(); + d->activeReaders = d->indexProvider->activeReaders(); + QStringList attributes = d->helpEngine->q->filterAttributes(d->currentFilter); + if (attributes.count() > 1) { + foreach (QHelpDBReader *r, d->activeReaders) + r->createAttributesCache(attributes, d->indexProvider->indexIds(r)); + } + filter(QString()); + emit indexCreated(); +} + +/*! + Returns true if the index is currently built up, otherwise + false. +*/ +bool QHelpIndexModel::isCreatingIndex() const +{ + return d->indexProvider->isRunning(); +} + +/*! + Returns all hits found for the \a keyword. A hit consists of + the URL and the document title. +*/ +QMap<QString, QUrl> QHelpIndexModel::linksForKeyword(const QString &keyword) const +{ + QMap<QString, QUrl> linkMap; + QStringList filterAttributes = d->helpEngine->q->filterAttributes(d->currentFilter); + foreach (QHelpDBReader *reader, d->activeReaders) + reader->linksForKeyword(keyword, filterAttributes, linkMap); + return linkMap; +} + +/*! + Filters the indices and returns the model index of the best + matching keyword. In a first step, only the keywords containing + \a filter are kept in the model's index list. Analogously, if + \a wildcard is not empty, only the keywords matched are left + in the index list. In a second step, the best match is + determined and its index model returned. When specifying a + wildcard expression, the \a filter string is used to + search for the best match. +*/ +QModelIndex QHelpIndexModel::filter(const QString &filter, const QString &wildcard) +{ + if (filter.isEmpty()) { + setStringList(d->indices); + return index(-1, 0, QModelIndex()); + } + + QStringList lst; + int goodMatch = -1; + int perfectMatch = -1; + + if (!wildcard.isEmpty()) { + QRegExp regExp(wildcard, Qt::CaseInsensitive); + regExp.setPatternSyntax(QRegExp::Wildcard); + foreach (QString index, d->indices) { + if (index.contains(regExp)) { + lst.append(index); + if (perfectMatch == -1 && index.startsWith(filter, Qt::CaseInsensitive)) { + if (goodMatch == -1) + goodMatch = lst.count()-1; + if (filter.length() == index.length()){ + perfectMatch = lst.count()-1; + } + } else if (perfectMatch > -1 && index == filter) { + perfectMatch = lst.count()-1; + } + } + } + } else { + foreach (QString index, d->indices) { + if (index.contains(filter, Qt::CaseInsensitive)) { + lst.append(index); + if (perfectMatch == -1 && index.startsWith(filter, Qt::CaseInsensitive)) { + if (goodMatch == -1) + goodMatch = lst.count()-1; + if (filter.length() == index.length()){ + perfectMatch = lst.count()-1; + } + } else if (perfectMatch > -1 && index == filter) { + perfectMatch = lst.count()-1; + } + } + } + + } + + if (perfectMatch == -1) + perfectMatch = qMax(0, goodMatch); + + setStringList(lst); + return index(perfectMatch, 0, QModelIndex()); +} + + + +/*! + \class QHelpIndexWidget + \inmodule QtHelp + \since 4.4 + \brief The QHelpIndexWidget class provides a list view + displaying the QHelpIndexModel. +*/ + +/*! + \fn void QHelpIndexWidget::linkActivated(const QUrl &link, + const QString &keyword) + + This signal is emitted when an item is activated and its + associated \a link should be shown. To know where the link + belongs to, the \a keyword is given as a second paremeter. +*/ + +/*! + \fn void QHelpIndexWidget::linksActivated(const QMap<QString, QUrl> &links, + const QString &keyword) + + This signal is emitted when the item representing the \a keyword + is activated and the item has more than one link associated. + The \a links consist of the document title and their URL. +*/ + +QHelpIndexWidget::QHelpIndexWidget() + : QListView(0) +{ + setEditTriggers(QAbstractItemView::NoEditTriggers); + setUniformItemSizes(true); + connect(this, SIGNAL(activated(const QModelIndex&)), + this, SLOT(showLink(const QModelIndex&))); +} + +void QHelpIndexWidget::showLink(const QModelIndex &index) +{ + if (!index.isValid()) + return; + + QHelpIndexModel *indexModel = qobject_cast<QHelpIndexModel*>(model()); + if (!indexModel) + return; + QVariant v = indexModel->data(index, Qt::DisplayRole); + QString name; + if (v.isValid()) + name = v.toString(); + + QMap<QString, QUrl> links = indexModel->linksForKeyword(name); + if (links.count() == 1) { + emit linkActivated(links.constBegin().value(), name); + } else if (links.count() > 1) { + emit linksActivated(links, name); + } +} + +/*! + Activates the current item which will result eventually in + the emitting of a linkActivated() or linksActivated() + signal. +*/ +void QHelpIndexWidget::activateCurrentItem() +{ + showLink(currentIndex()); +} + +/*! + Filters the indices according to \a filter or \a wildcard. + The item with the best match is set as current item. + + \sa QHelpIndexModel::filter() +*/ +void QHelpIndexWidget::filterIndices(const QString &filter, const QString &wildcard) +{ + QHelpIndexModel *indexModel = qobject_cast<QHelpIndexModel*>(model()); + if (!indexModel) + return; + QModelIndex idx = indexModel->filter(filter, wildcard); + if (idx.isValid()) + setCurrentIndex(idx); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpindexwidget.h b/tools/assistant/lib/qhelpindexwidget.h new file mode 100644 index 0000000..46b9e4c --- /dev/null +++ b/tools/assistant/lib/qhelpindexwidget.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPINDEXWIDGET_H +#define QHELPINDEXWIDGET_H + +#include <QtHelp/qhelp_global.h> + +#include <QtCore/QUrl> +#include <QtGui/QStringListModel> +#include <QtGui/QListView> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Help) + +class QHelpEnginePrivate; +class QHelpIndexModelPrivate; + +class QHELP_EXPORT QHelpIndexModel : public QStringListModel +{ + Q_OBJECT + +public: + void createIndex(const QString &customFilterName); + QModelIndex filter(const QString &filter, + const QString &wildcard = QString()); + + QMap<QString, QUrl> linksForKeyword(const QString &keyword) const; + bool isCreatingIndex() const; + +Q_SIGNALS: + void indexCreationStarted(); + void indexCreated(); + +private Q_SLOTS: + void insertIndices(); + void invalidateIndex(bool onShutDown = false); + +private: + QHelpIndexModel(QHelpEnginePrivate *helpEngine); + ~QHelpIndexModel(); + + QHelpIndexModelPrivate *d; + friend class QHelpEnginePrivate; +}; + +class QHELP_EXPORT QHelpIndexWidget : public QListView +{ + Q_OBJECT + +Q_SIGNALS: + void linkActivated(const QUrl &link, const QString &keyword); + void linksActivated(const QMap<QString, QUrl> &links, + const QString &keyword); + +public Q_SLOTS: + void filterIndices(const QString &filter, + const QString &wildcard = QString()); + void activateCurrentItem(); + +private Q_SLOTS: + void showLink(const QModelIndex &index); + +private: + QHelpIndexWidget(); + friend class QHelpEngine; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/tools/assistant/lib/qhelpprojectdata.cpp b/tools/assistant/lib/qhelpprojectdata.cpp new file mode 100644 index 0000000..fcb8cf6 --- /dev/null +++ b/tools/assistant/lib/qhelpprojectdata.cpp @@ -0,0 +1,374 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpprojectdata_p.h" + +#include <QtCore/QFileInfo> +#include <QtCore/QStack> +#include <QtCore/QMap> +#include <QtCore/QVariant> +#include <QtXml/QXmlStreamReader> + +QT_BEGIN_NAMESPACE + +class QHelpProjectDataPrivate : public QXmlStreamReader +{ +public: + void readData(const QByteArray &contents); + + QString virtualFolder; + QString namespaceName; + QString rootPath; + + QStringList fileList; + QList<QHelpDataCustomFilter> customFilterList; + QList<QHelpDataFilterSection> filterSectionList; + QMap<QString, QVariant> metaData; + + QString errorMsg; + +private: + void readProject(); + void readCustomFilter(); + void readFilterSection(); + void readTOC(); + void readKeywords(); + void readFiles(); + void raiseUnknownTokenError(); +}; + +void QHelpProjectDataPrivate::raiseUnknownTokenError() +{ + raiseError(QObject::tr("Unknown token.")); +} + +void QHelpProjectDataPrivate::readData(const QByteArray &contents) +{ + addData(contents); + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("QtHelpProject") + && attributes().value(QLatin1String("version")) == QLatin1String("1.0")) + readProject(); + else + raiseError(QObject::tr("Unknown token. Expected \"QtHelpProject\"!")); + } + } + + if (hasError()) { + raiseError(QObject::tr("Error in line %1: %2").arg(lineNumber()) + .arg(errorString())); + } +} + +void QHelpProjectDataPrivate::readProject() +{ + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("virtualFolder")) { + virtualFolder = readElementText(); + if (virtualFolder.contains(QLatin1String("/"))) + raiseError(QObject::tr("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!")); + } else if (name() == QLatin1String("customFilter")) { + readCustomFilter(); + } else if (name() == QLatin1String("filterSection")) { + readFilterSection(); + } else if (name() == QLatin1String("metaData")) { + QString n = attributes().value(QLatin1String("name")).toString(); + if (!metaData.contains(n)) + metaData[n] = attributes().value(QLatin1String("value")).toString(); + else + 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.")); + else if (virtualFolder.isEmpty()) + raiseError(QObject::tr("Missing virtual folder in QtHelpProject")); + break; + } + } +} + +void QHelpProjectDataPrivate::readCustomFilter() +{ + QHelpDataCustomFilter filter; + filter.name = attributes().value(QLatin1String("name")).toString(); + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("filterAttribute")) + filter.filterAttributes.append(readElementText()); + else + raiseUnknownTokenError(); + } else if (isEndElement() && name() == QLatin1String("customFilter")) { + break; + } + } + customFilterList.append(filter); +} + +void QHelpProjectDataPrivate::readFilterSection() +{ + filterSectionList.append(QHelpDataFilterSection()); + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("filterAttribute")) + filterSectionList.last().addFilterAttribute(readElementText()); + else if (name() == QLatin1String("toc")) + readTOC(); + else if (name() == QLatin1String("keywords")) + readKeywords(); + else if (name() == QLatin1String("files")) + readFiles(); + else + raiseUnknownTokenError(); + } else if (isEndElement() && name() == QLatin1String("filterSection")) { + break; + } + } +} + +void QHelpProjectDataPrivate::readTOC() +{ + QStack<QHelpDataContentItem*> contentStack; + QHelpDataContentItem *itm = 0; + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("section")) { + QString title = attributes().value(QLatin1String("title")).toString(); + QString ref = attributes().value(QLatin1String("ref")).toString(); + if (contentStack.isEmpty()) { + itm = new QHelpDataContentItem(0, title, ref); + filterSectionList.last().addContent(itm); + } else { + itm = new QHelpDataContentItem(contentStack.top(), title, ref); + } + contentStack.push(itm); + } else { + raiseUnknownTokenError(); + } + } else if (isEndElement()) { + if (name() == QLatin1String("section")) { + contentStack.pop(); + continue; + } else if (name() == QLatin1String("toc") && contentStack.isEmpty()) { + break; + } else { + raiseUnknownTokenError(); + } + } + } +} + +void QHelpProjectDataPrivate::readKeywords() +{ + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("keyword")) { + 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())); + } else { + raiseUnknownTokenError(); + } + } else if (isEndElement()) { + if (name() == QLatin1String("keyword")) + continue; + else if (name() == QLatin1String("keywords")) + break; + else + raiseUnknownTokenError(); + } + } +} + +void QHelpProjectDataPrivate::readFiles() +{ + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("file")) + filterSectionList.last().addFile(readElementText()); + else + raiseUnknownTokenError(); + } else if (isEndElement()) { + if (name() == QLatin1String("file")) + continue; + else if (name() == QLatin1String("files")) + break; + else + raiseUnknownTokenError(); + } + } +} + + + +/*! + \internal + \class QHelpProjectData + \since 4.4 + \brief The QHelpProjectData class stores all information found + in a Qt help project file. + + The structure is filled with data by calling readData(). The + specified file has to have the Qt help project file format in + order to be read successfully. Possible reading errors can be + retrieved by calling errorMessage(). +*/ + +/*! + Constructs a Qt help project data structure. +*/ +QHelpProjectData::QHelpProjectData() +{ + d = new QHelpProjectDataPrivate; +} + +/*! + Destroys the help project data. +*/ +QHelpProjectData::~QHelpProjectData() +{ + delete d; +} + +/*! + Reads the file \a fileName and stores the help data. The file has to + have the Qt help project file format. Returns true if the file + was successfully read, otherwise false. + + \sa errorMessage() +*/ +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); + return false; + } + + d->readData(file.readAll()); + return !d->hasError(); +} + +/*! + Returns an error message if the reading of the Qt help project + file failed. Otherwise, an empty QString is returned. + + \sa readData() +*/ +QString QHelpProjectData::errorMessage() const +{ + if (d->hasError()) + return d->errorString(); + return d->errorMsg; +} + +/*! + \reimp +*/ +QString QHelpProjectData::namespaceName() const +{ + return d->namespaceName; +} + +/*! + \reimp +*/ +QString QHelpProjectData::virtualFolder() const +{ + return d->virtualFolder; +} + +/*! + \reimp +*/ +QList<QHelpDataCustomFilter> QHelpProjectData::customFilters() const +{ + return d->customFilterList; +} + +/*! + \reimp +*/ +QList<QHelpDataFilterSection> QHelpProjectData::filterSections() const +{ + return d->filterSectionList; +} + +/*! + \reimp +*/ +QMap<QString, QVariant> QHelpProjectData::metaData() const +{ + return d->metaData; +} + +/*! + \reimp +*/ +QString QHelpProjectData::rootPath() const +{ + return d->rootPath; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpprojectdata_p.h b/tools/assistant/lib/qhelpprojectdata_p.h new file mode 100644 index 0000000..52eb723 --- /dev/null +++ b/tools/assistant/lib/qhelpprojectdata_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPPROJECTDATA_H +#define QHELPPROJECTDATA_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhelp_global.h" +#include "qhelpdatainterface_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QHelpProjectDataPrivate; + +class QHELP_EXPORT QHelpProjectData : public QHelpDataInterface +{ +public: + QHelpProjectData(); + ~QHelpProjectData(); + + bool readData(const QString &fileName); + QString errorMessage() const; + + QString namespaceName() const; + QString virtualFolder() const; + QList<QHelpDataCustomFilter> customFilters() const; + QList<QHelpDataFilterSection> filterSections() const; + QMap<QString, QVariant> metaData() const; + QString rootPath() const; + +private: + QHelpProjectDataPrivate *d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/tools/assistant/lib/qhelpsearchengine.cpp b/tools/assistant/lib/qhelpsearchengine.cpp new file mode 100644 index 0000000..9025f4f --- /dev/null +++ b/tools/assistant/lib/qhelpsearchengine.cpp @@ -0,0 +1,445 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpenginecore.h" +#include "qhelpsearchengine.h" +#include "qhelpsearchquerywidget.h" +#include "qhelpsearchresultwidget.h" + +#if defined(QT_CLUCENE_SUPPORT) +# include "qhelpsearchindexreader_clucene_p.h" +# include "qhelpsearchindexwriter_clucene_p.h" +#else +# include "qhelpsearchindexreader_default_p.h" +# include "qhelpsearchindexwriter_default_p.h" +#endif + +#include <QtCore/QDir> +#include <QtCore/QFile> +#include <QtCore/QFileInfo> +#include <QtCore/QVariant> +#include <QtCore/QThread> +#include <QtCore/QPointer> + +QT_BEGIN_NAMESPACE + +#if defined(QT_CLUCENE_SUPPORT) + using namespace qt::fulltextsearch::clucene; +#else + using namespace qt::fulltextsearch::std; +#endif + +class QHelpSearchEnginePrivate : public QObject +{ + Q_OBJECT + +signals: + void indexingStarted(); + void indexingFinished(); + + void searchingStarted(); + void searchingFinished(int hits); + +private: + QHelpSearchEnginePrivate(QHelpEngineCore *helpEngine) + : queryWidget(0) + , resultWidget(0) + , helpEngine(helpEngine) + { + hitList.clear(); + indexReader = 0; + indexWriter = 0; + } + + ~QHelpSearchEnginePrivate() + { + hitList.clear(); + delete indexReader; + delete indexWriter; + } + + int hitsCount() const + { + int count = 0; + if (indexReader) + count = indexReader->hitsCount(); + + return count; + } + + QList<QHelpSearchEngine::SearchHit> hits(int start, int end) const + { + QList<QHelpSearchEngine::SearchHit> returnValue; + if (indexReader) { + for (int i = start; i < end && i < hitsCount(); ++i) + returnValue.append(indexReader->hit(i)); + } + return returnValue; + } + + void updateIndex(bool reindex = false) + { + if (helpEngine.isNull()) + return; + + if (!QFile::exists(QFileInfo(helpEngine->collectionFile()).path())) + return; + + if (!indexWriter) { + indexWriter = new QHelpSearchIndexWriter(); + + connect(indexWriter, SIGNAL(indexingStarted()), this, SIGNAL(indexingStarted())); + connect(indexWriter, SIGNAL(indexingFinished()), this, SIGNAL(indexingFinished())); + connect(indexWriter, SIGNAL(indexingFinished()), this, SLOT(optimizeIndex())); + } + + if (indexWriter) { + indexWriter->cancelIndexing(); + indexWriter->updateIndex(helpEngine->collectionFile(), + indexFilesFolder(), reindex); + } + } + + void cancelIndexing() + { + if (indexWriter) + indexWriter->cancelIndexing(); + } + + void search(const QList<QHelpSearchQuery> &queryList) + { + if (helpEngine.isNull()) + return; + + if (!QFile::exists(QFileInfo(helpEngine->collectionFile()).path())) + return; + + if (!indexReader) { + indexReader = new QHelpSearchIndexReader(); + + connect(indexReader, SIGNAL(searchingStarted()), this, SIGNAL(searchingStarted())); + connect(indexReader, SIGNAL(searchingFinished(int)), this, SIGNAL(searchingFinished(int))); + } + + if (indexReader) { + m_queryList = queryList; + indexReader->cancelSearching(); + indexReader->search(helpEngine->collectionFile(), indexFilesFolder(), queryList); + } + } + + void cancelSearching() + { + if (indexReader) + indexReader->cancelSearching(); + } + + QString indexFilesFolder() const + { + QString indexFilesFolder = QLatin1String(".fulltextsearch"); + if (helpEngine && !helpEngine->collectionFile().isEmpty()) { + QFileInfo fi(helpEngine->collectionFile()); + indexFilesFolder = fi.absolutePath() + QDir::separator() + + QLatin1Char('.') + + fi.fileName().left(fi.fileName().lastIndexOf(QLatin1String(".qhc"))); + } + return indexFilesFolder; + } + +private slots: + void optimizeIndex() + { +#if defined(QT_CLUCENE_SUPPORT) + if (indexWriter && !helpEngine.isNull()) { + indexWriter->optimizeIndex(); + } +#endif + } + +private: + friend class QHelpSearchEngine; + + QHelpSearchQueryWidget *queryWidget; + QHelpSearchResultWidget *resultWidget; + + QHelpSearchIndexReader *indexReader; + QHelpSearchIndexWriter *indexWriter; + + QPointer<QHelpEngineCore> helpEngine; + QList<QHelpSearchEngine::SearchHit> hitList; + + QList<QHelpSearchQuery> m_queryList; +}; + +#include "qhelpsearchengine.moc" + + +/*! + \class QHelpSearchQuery + \since 4.4 + \inmodule QtHelp + \brief The QHelpSearchQuery class contains the field name and the associated + search term + + The QHelpSearchQuery class contains the field name and the associated search + term. Depending on the field the search term might get split up into seperate + terms to be parsed differently by the search engine. + + \sa QHelpSearchQueryWidget +*/ + +/*! + \fn QHelpSearchQuery::QHelpSearchQuery() + + Constructs a new empty QHelpSearchQuery. +*/ + +/*! + \fn QHelpSearchQuery::QHelpSearchQuery(FieldName field, const QStringList &wordList) + + Constructs a new QHelpSearchQuery and initializes it with the given \a field and \a wordList. +*/ + +/*! + \enum QHelpSearchQuery::FieldName + This enum type specifies the field names that are handled by the search engine. + + \value DEFAULT the default field provided by the search widget, several terms should be + splitted and stored in the wordlist except search terms enclosed in quotes. + \value FUZZY a field only provided in use with clucene. Terms should be split in seperate + words and passed to the search engine. + \value WITHOUT a field only provided in use with clucene. Terms should be split in seperate + words and passed to the search engine. + \value PHRASE a field only provided in use with clucene. Terms should not be split in seperate + words. + \value ALL a field only provided in use with clucene. Terms should be split in seperate + words and passed to the search engine + \value ATLEAST a field only provided in use with clucene. Terms should be split in seperate + words and passed to the search engine +*/ + +/*! + \class QHelpSearchEngine + \since 4.4 + \inmodule QtHelp + \brief The QHelpSearchEngine class provides access to widgets reusable + to integrate fulltext search as well as to index and search documentation. + + Before the search engine can be used, one has to instantiate at least a + QHelpEngineCore object that needs to be passed to the search engines constructor. + This is required as the search engine needs to be connected to the help + engines setupFinished() signal to know when it can start to index documentation. + + After starting the indexing process the signal indexingStarted() is emitted and + on the end of the indexing process the indexingFinished() is emited. To stop + the indexing one can call cancelIndexing(). + + While the indexing process has finished, the search engine can now be used to search + thru its index for a given term. To do this one may use the possibility of creating the + QHelpSearchQuery list by self or reuse the QHelpSearchQueryWidget which has the inbuild + functionality to set up a proper search querys list that get's passed to the search engines + search() function. + + After the list of querys has been passed to the search engine, the signal searchingStarted() + is emited and after the search has finished the searchingFinished() signal is emited. The + search process can be stopped by calling cancelSearching(). + + If the search succeeds, the searchingFinished() will be called with the search hits count, + which can be reused to fetch the search hits from the search engine. Calling the hits() + function with the range of hits you would like to get will return a list of the requested + SearchHits. They basically constist at the moment of a pair of strings where the values + of that pair are the documentation file path and the page title. + + To display the given hits use the QHelpSearchResultWidget or build up your own one if you need + more advanced functionality. Note that the QHelpSearchResultWidget can not be instantiated + directly, you must retrieve the widget from the search engine in use as all connections will be + established for you by the widget itself. +*/ + +/*! + \fn void QHelpSearchEngine::indexingStarted() + + This signal is emitted when indexing process is started. +*/ + +/*! + \fn void QHelpSearchEngine::indexingFinished() + + This signal is emitted when the indexing process is complete. +*/ + +/*! + \fn void QHelpSearchEngine::searchingStarted() + + This signal is emitted when the search process is started. +*/ + +/*! + \fn void QHelpSearchEngine::searchingFinished(int hits) + + This signal is emitted when the search process is complete. + The hit count is stored in \a hits. +*/ + +/*! + Constructs a new search engine with the given \a parent. The search engine + uses the given \a helpEngine to access the documentation that needs to be indexed. + The QHelpEngine's setupFinished() signal is automatically connected to the + QHelpSearchEngine's indexing function, so that new documentation will be indexed + after the signal is emited. +*/ +QHelpSearchEngine::QHelpSearchEngine(QHelpEngineCore *helpEngine, QObject *parent) + : QObject(parent) +{ + d = new QHelpSearchEnginePrivate(helpEngine); + + connect(helpEngine, SIGNAL(setupFinished()), this, SLOT(indexDocumentation())); + + connect(d, SIGNAL(indexingStarted()), this, SIGNAL(indexingStarted())); + connect(d, SIGNAL(indexingFinished()), this, SIGNAL(indexingFinished())); + connect(d, SIGNAL(searchingStarted()), this, SIGNAL(searchingStarted())); + connect(d, SIGNAL(searchingFinished(int)), this, SIGNAL(searchingFinished(int))); +} + +/*! + Destructs the search engine. +*/ +QHelpSearchEngine::~QHelpSearchEngine() +{ + delete d; +} + +/*! + Returns a widget to use as input widget. Depending on your search engine + configuration you will get a different widget with more or less subwidgets. +*/ +QHelpSearchQueryWidget* QHelpSearchEngine::queryWidget() +{ + if (!d->queryWidget) + d->queryWidget = new QHelpSearchQueryWidget(); + + return d->queryWidget; +} + +/*! + Returns a widget that can hold and display the search results. +*/ +QHelpSearchResultWidget* QHelpSearchEngine::resultWidget() +{ + if (!d->resultWidget) + d->resultWidget = new QHelpSearchResultWidget(this); + + return d->resultWidget; +} + +/*! + Returns the amount of hits the search engine found. +*/ +int QHelpSearchEngine::hitsCount() const +{ + return d->hitsCount(); +} + +/*! + \typedef QHelpSearchEngine::SearchHit + + Typedef for QPair<QString, QString>. + The values of that pair are the documentation file path and the page title. + + \sa hits() +*/ + +/*! + Returns a list of search hits within the range of \a start \a end. +*/ +QList<QHelpSearchEngine::SearchHit> QHelpSearchEngine::hits(int start, int end) const +{ + return d->hits(start, end); +} + +/*! + Returns the list of queries last searched for. + \since 4.5 +*/ +QList<QHelpSearchQuery> QHelpSearchEngine::query() const +{ + return d->m_queryList; +} + +/*! + Forces the search engine to reindex all documentation files. +*/ +void QHelpSearchEngine::reindexDocumentation() +{ + d->updateIndex(true); +} + +/*! + Stops the indexing process. +*/ +void QHelpSearchEngine::cancelIndexing() +{ + d->cancelIndexing(); +} + +/*! + Stops the search process. +*/ +void QHelpSearchEngine::cancelSearching() +{ + d->cancelSearching(); +} + +/*! + Starts the search process using the given list of querys \a queryList + build by the search field name and the values to search for. +*/ +void QHelpSearchEngine::search(const QList<QHelpSearchQuery> &queryList) +{ + d->search(queryList); +} + +void QHelpSearchEngine::indexDocumentation() +{ + d->updateIndex(); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpsearchengine.h b/tools/assistant/lib/qhelpsearchengine.h new file mode 100644 index 0000000..bd14d3e --- /dev/null +++ b/tools/assistant/lib/qhelpsearchengine.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHENGINE_H +#define QHELPSEARCHENGINE_H + +#include <QtHelp/qhelp_global.h> + +#include <QtCore/QMap> +#include <QtCore/QUrl> +#include <QtCore/QObject> +#include <QtCore/QString> +#include <QtCore/QStringList> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Help) + +class QHelpEngineCore; +class QHelpSearchQueryWidget; +class QHelpSearchResultWidget; +class QHelpSearchEnginePrivate; + +class QHELP_EXPORT QHelpSearchQuery +{ +public: + enum FieldName { DEFAULT = 0, FUZZY, WITHOUT, PHRASE, ALL, ATLEAST }; + + QHelpSearchQuery() + : fieldName(DEFAULT) { wordList.clear(); } + QHelpSearchQuery(FieldName field, const QStringList &wordList) + : fieldName(field), wordList(wordList) {} + + FieldName fieldName; + QStringList wordList; +}; + +class QHELP_EXPORT QHelpSearchEngine : public QObject +{ + Q_OBJECT + +public: + QHelpSearchEngine(QHelpEngineCore *helpEngine, QObject *parent = 0); + ~QHelpSearchEngine(); + + QHelpSearchQueryWidget* queryWidget(); + QHelpSearchResultWidget* resultWidget(); + + int hitsCount() const; + + typedef QPair<QString, QString> SearchHit; + QList<SearchHit> hits(int start, int end) const; + + QList<QHelpSearchQuery> query() const; + +public Q_SLOTS: + void reindexDocumentation(); + void cancelIndexing(); + + void search(const QList<QHelpSearchQuery> &queryList); + void cancelSearching(); + +Q_SIGNALS: + void indexingStarted(); + void indexingFinished(); + + void searchingStarted(); + void searchingFinished(int hits); + +private Q_SLOTS: + void indexDocumentation(); + +private: + QHelpSearchEnginePrivate *d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QHELPSEARCHENGINE_H diff --git a/tools/assistant/lib/qhelpsearchindex_default.cpp b/tools/assistant/lib/qhelpsearchindex_default.cpp new file mode 100644 index 0000000..defba91 --- /dev/null +++ b/tools/assistant/lib/qhelpsearchindex_default.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpsearchindex_default_p.h" + +QT_BEGIN_NAMESPACE + +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; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpsearchindex_default_p.h b/tools/assistant/lib/qhelpsearchindex_default_p.h new file mode 100644 index 0000000..b9ada2d --- /dev/null +++ b/tools/assistant/lib/qhelpsearchindex_default_p.h @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHINDEXDEFAULT_H +#define QHELPSEARCHINDEXDEFAULT_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QString> +#include <QtCore/QVector> +#include <QtCore/QDataStream> + +QT_BEGIN_NAMESPACE + +namespace QtHelpInternal { + +struct Document { + Document(qint16 d, qint16 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; +}; + +struct DocumentInfo : public Document { + DocumentInfo() + : Document(-1, 0), documentTitle(QString()), documentUrl(QString()) {} + + DocumentInfo(qint16 d, qint16 f, const QString &title, const QString &url) + : Document(d, f), documentTitle(title), documentUrl(url) {} + + DocumentInfo(const Document &document, const QString &title, const QString &url) + : Document(document.docNumber, document.frequency), documentTitle(title), documentUrl(url) {} + + QString documentTitle; + QString documentUrl; +}; + +struct Entry { + Entry(qint16 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; +}; + +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; } +}; + +struct TermInfo { + TermInfo() : frequency(-1) {} + TermInfo(const QString &t, int f, QVector<DocumentInfo> l) + : term(t), frequency(f), documents(l) {} + + bool operator<(const TermInfo &i2) const { return frequency < i2.frequency; } + + QString term; + int frequency; + QVector<DocumentInfo>documents; +}; + +} // namespace QtHelpInternal + +using QtHelpInternal::Document; +using QtHelpInternal::DocumentInfo; +using QtHelpInternal::Entry; +using QtHelpInternal::PosEntry; +using QtHelpInternal::Term; +using QtHelpInternal::TermInfo; + +QDataStream &operator>>(QDataStream &s, Document &l); +QDataStream &operator<<(QDataStream &s, const Document &l); + +QT_END_NAMESPACE + +#endif // QHELPSEARCHINDEXDEFAULT_H diff --git a/tools/assistant/lib/qhelpsearchindexreader_clucene.cpp b/tools/assistant/lib/qhelpsearchindexreader_clucene.cpp new file mode 100644 index 0000000..82a3a17 --- /dev/null +++ b/tools/assistant/lib/qhelpsearchindexreader_clucene.cpp @@ -0,0 +1,392 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpenginecore.h" +#include "fulltextsearch/qsearchable_p.h" +#include "fulltextsearch/qqueryparser_p.h" +#include "fulltextsearch/qindexreader_p.h" +#include "qhelpsearchindexreader_clucene_p.h" + +#include <QtCore/QDir> +#include <QtCore/QSet> +#include <QtCore/QString> +#include <QtCore/QFileInfo> +#include <QtCore/QStringList> +#include <QtCore/QTextStream> +#include <QtCore/QMutexLocker> + +QT_BEGIN_NAMESPACE + +namespace qt { + namespace fulltextsearch { + namespace clucene { + +QHelpSearchIndexReader::QHelpSearchIndexReader() + : QThread() + , m_cancel(false) +{ + // nothing todo +} + +QHelpSearchIndexReader::~QHelpSearchIndexReader() +{ + mutex.lock(); + this->m_cancel = true; + waitCondition.wakeOne(); + mutex.unlock(); + + wait(); +} + +void QHelpSearchIndexReader::cancelSearching() +{ + mutex.lock(); + this->m_cancel = true; + mutex.unlock(); +} + +void QHelpSearchIndexReader::search(const QString &collectionFile, + const QString &indexFilesFolder, + const QList<QHelpSearchQuery> &queryList) +{ + QMutexLocker lock(&mutex); + + this->hitList.clear(); + this->m_cancel = false; + this->m_query = queryList; + this->m_collectionFile = collectionFile; + this->m_indexFilesFolder = indexFilesFolder; + + start(QThread::NormalPriority); +} + +int QHelpSearchIndexReader::hitsCount() const +{ + return hitList.count(); +} + +QHelpSearchEngine::SearchHit QHelpSearchIndexReader::hit(int index) const +{ + return hitList.at(index); +} + +void QHelpSearchIndexReader::run() +{ + mutex.lock(); + + if (m_cancel) { + mutex.unlock(); + return; + } + + const QString collectionFile(this->m_collectionFile); + const QList<QHelpSearchQuery> &queryList = this->m_query; + const QString indexPath(m_indexFilesFolder); + + mutex.unlock(); + + QHelpEngineCore engine(collectionFile, 0); + if (!engine.setupData()) + return; + + QFileInfo fInfo(indexPath); + if (fInfo.exists() && !fInfo.isWritable()) { + qWarning("Full Text Search, could not read index (missing permissions)."); + return; + } + + if(QCLuceneIndexReader::indexExists(indexPath)) { + mutex.lock(); + if (m_cancel) { + mutex.unlock(); + return; + } + mutex.unlock(); + + emit searchingStarted(); + +#if !defined(QT_NO_EXCEPTIONS) + try { +#endif + QCLuceneBooleanQuery booleanQuery; + if (!buildQuery(booleanQuery, queryList)) { + emit searchingFinished(0); + return; + } + + const QStringList attribList = engine.filterAttributes(engine.currentFilter()); + if (!attribList.isEmpty()) { + QCLuceneStandardAnalyzer analyzer; + QCLuceneQuery* query = QCLuceneQueryParser::parse(QLatin1String("+") + + attribList.join(QLatin1String(" +")), QLatin1String("attribute"), + analyzer); + + if (!query) { + emit searchingFinished(0); + return; + } + booleanQuery.add(query, true, true, false); + } + + QCLuceneIndexSearcher indexSearcher(indexPath); + QCLuceneHits hits = indexSearcher.search(booleanQuery); + const QStringList namespaceList = engine.registeredDocumentations(); + + QSet<QString> pathSet; + QCLuceneDocument document; + 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(); + + mutex.lock(); + if (m_cancel) { + mutex.unlock(); + emit searchingFinished(0); + return; + } + mutex.unlock(); + } + + indexSearcher.close(); + int count = hitList.count(); + if (count > 0) + boostSearchHits(engine, hitList, queryList); + emit searchingFinished(hitList.count()); + +#if !defined(QT_NO_EXCEPTIONS) + } catch(...) { + hitList.clear(); + emit searchingFinished(0); + } +#endif + } +} + +bool QHelpSearchIndexReader::defaultQuery(const QString &term, + QCLuceneBooleanQuery &booleanQuery) +{ + QCLuceneStandardAnalyzer 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; + } + + return false; +} + +bool QHelpSearchIndexReader::buildQuery(QCLuceneBooleanQuery &booleanQuery, + const QList<QHelpSearchQuery> &queryList) +{ + 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)) + 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 t, termList) { + if (!stopWords.contains(t, Qt::CaseInsensitive)) + q->addTerm(QCLuceneTerm(QLatin1String("content"), t.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; + + case QHelpSearchQuery::ALL: { + 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())); + + if (query) { + booleanQuery.add(query, true, true, false); + } else { + return false; + } + } + } break; + + case QHelpSearchQuery::DEFAULT: { + QCLuceneStandardAnalyzer analyzer; + foreach (const QString t, query.wordList) { + QCLuceneQuery *query = QCLuceneQueryParser::parse(t.toLower(), + QLatin1String("content"), analyzer); + + if (query) + booleanQuery.add(query, true, true, false); + } + } break; + + case QHelpSearchQuery::ATLEAST: { + foreach (const QString term, query.wordList) { + if (term.isEmpty() || !defaultQuery(term.toLower(), booleanQuery)) + return false; + } + } + } + } + + return true; +} + +void QHelpSearchIndexReader::boostSearchHits(const QHelpEngineCore &engine, + QList<QHelpSearchEngine::SearchHit> &hitList, + const QList<QHelpSearchQuery> &queryList) +{ + foreach (const QHelpSearchQuery query, queryList) { + if (query.fieldName != QHelpSearchQuery::DEFAULT) + continue; + + QString joinedQuery = query.wordList.join(QLatin1String(" ")); + + QCLuceneStandardAnalyzer analyzer; + QCLuceneQuery *parsedQuery = QCLuceneQueryParser::parse( + joinedQuery, QLatin1String("content"), analyzer); + + if (parsedQuery) { + joinedQuery = parsedQuery->toString(); + delete parsedQuery; + } + + int length = QString(QLatin1String("content:")).length(); + int index = joinedQuery.indexOf(QLatin1String("content:")); + + QString term; + int nextIndex = 0; + QStringList searchTerms; + while (index != -1) { + nextIndex = joinedQuery.indexOf(QLatin1String("content:"), index + 1); + term = joinedQuery.mid(index + length, nextIndex - (length + index)) + .simplified(); + if (term.startsWith(QLatin1String("\"")) + && term.endsWith(QLatin1String("\""))) { + searchTerms.append(term.remove(QLatin1String("\""))); + } else { + searchTerms += term.split(QLatin1Char(' ')); + } + index = nextIndex; + } + searchTerms.removeDuplicates(); + + int count = qMin(75, hitList.count()); + QMap<int, QHelpSearchEngine::SearchHit> hitMap; + for (int i = 0; i < count; ++i) { + const QHelpSearchEngine::SearchHit &hit = hitList.at(i); + QString data = QString::fromUtf8(engine.fileData(hit.first)); + + int counter = 0; + foreach (const QString& term, searchTerms) + counter += data.count(term, Qt::CaseInsensitive); + hitMap.insertMulti(counter, hit); + } + + QList<QHelpSearchEngine::SearchHit> boostedList; + QMap<int, QHelpSearchEngine::SearchHit>::const_iterator i; + for (i = hitMap.constEnd(), --i; i != hitMap.constBegin(); --i) + boostedList.append(i.value()); + boostedList += hitList.mid(count - 1, hitList.count()); + + hitList = boostedList; + } +} + + } // namespace clucene + } // namespace fulltextsearch +} // namespace qt + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpsearchindexreader_clucene_p.h b/tools/assistant/lib/qhelpsearchindexreader_clucene_p.h new file mode 100644 index 0000000..892c4e6 --- /dev/null +++ b/tools/assistant/lib/qhelpsearchindexreader_clucene_p.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHINDEXREADERCLUCENE_H +#define QHELPSEARCHINDEXREADERCLUCENE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhelpsearchengine.h" +#include "fulltextsearch/qquery_p.h" + +#include <QtCore/QList> +#include <QtCore/QMutex> +#include <QtCore/QObject> +#include <QtCore/QString> +#include <QtCore/QThread> +#include <QtCore/QWaitCondition> + +class QHelpEngineCore; + +QT_BEGIN_NAMESPACE + +namespace qt { + namespace fulltextsearch { + namespace clucene { + +class QHelpSearchIndexReader : public QThread +{ + Q_OBJECT + +public: + QHelpSearchIndexReader(); + ~QHelpSearchIndexReader(); + + void cancelSearching(); + void search(const QString &collectionFile, + const QString &indexFilesFolder, + const QList<QHelpSearchQuery> &queryList); + + int hitsCount() const; + QHelpSearchEngine::SearchHit hit(int index) const; + +signals: + void searchingStarted(); + void searchingFinished(int hits); + +private: + void run(); + bool defaultQuery(const QString &term, + QCLuceneBooleanQuery &booleanQuery); + bool buildQuery(QCLuceneBooleanQuery &booleanQuery, + const QList<QHelpSearchQuery> &queryList); + void boostSearchHits(const QHelpEngineCore &engine, + QList<QHelpSearchEngine::SearchHit> &hitList, + const QList<QHelpSearchQuery> &queryList); + +private: + QMutex mutex; + QList<QHelpSearchEngine::SearchHit> hitList; + QWaitCondition waitCondition; + + bool m_cancel; + QString m_collectionFile; + QList<QHelpSearchQuery> m_query; + QString m_indexFilesFolder; +}; + + } // namespace clucene + } // namespace fulltextsearch +} // namespace qt + +QT_END_NAMESPACE + +#endif // QHELPSEARCHINDEXREADERCLUCENE_H diff --git a/tools/assistant/lib/qhelpsearchindexreader_default.cpp b/tools/assistant/lib/qhelpsearchindexreader_default.cpp new file mode 100644 index 0000000..617d0d2 --- /dev/null +++ b/tools/assistant/lib/qhelpsearchindexreader_default.cpp @@ -0,0 +1,653 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpenginecore.h" +#include "qhelpsearchindexreader_default_p.h" + +#include <QtCore/QDir> +#include <QtCore/QUrl> +#include <QtCore/QFile> +#include <QtCore/QVariant> +#include <QtCore/QFileInfo> +#include <QtCore/QDataStream> +#include <QtCore/QTextStream> + +QT_BEGIN_NAMESPACE + +namespace qt { + namespace fulltextsearch { + namespace std { + +namespace { + QStringList 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; + } +} + + +Reader::Reader() + : indexPath(QString()) + , indexFile(QString()) + , documentFile(QString()) +{ + termList.clear(); + indexTable.clear(); + searchIndexTable.clear(); +} + +Reader::~Reader() +{ + reset(); + searchIndexTable.clear(); +} + +bool Reader::readIndex() +{ + if (indexTable.contains(indexFile)) + return true; + + QFile idxFile(indexFile); + if (!idxFile.open(QFile::ReadOnly)) + return false; + + QString key; + int numOfDocs; + EntryTable entryTable; + QVector<Document> docs; + QDataStream dictStream(&idxFile); + while (!dictStream.atEnd()) { + dictStream >> key; + dictStream >> numOfDocs; + docs.resize(numOfDocs); + dictStream >> docs; + entryTable.insert(key, new Entry(docs)); + } + idxFile.close(); + + if (entryTable.isEmpty()) + return false; + + QFile docFile(documentFile); + if (!docFile.open(QFile::ReadOnly)) + return false; + + QString title, url; + DocumentList documentList; + QDataStream docStream(&docFile); + while (!docStream.atEnd()) { + docStream >> title; + docStream >> url; + documentList.append(QStringList(title) << url); + } + docFile.close(); + + if (documentList.isEmpty()) { + cleanupIndex(entryTable); + return false; + } + + indexTable.insert(indexFile, Index(entryTable, documentList)); + return true; +} + +bool Reader::initCheck() const +{ + return !searchIndexTable.isEmpty(); +} + +void Reader::setIndexPath(const QString &path) +{ + indexPath = path; +} + +void Reader::filterFilesForAttributes(const QStringList &attributes) +{ + searchIndexTable.clear(); + for(IndexTable::ConstIterator it = indexTable.begin(); it != indexTable.end(); ++it) { + const QString fileName = it.key(); + bool containsAll = true; + QStringList split = fileName.split(QLatin1String("@")); + foreach (const QString attribute, attributes) { + if (!split.contains(attribute, Qt::CaseInsensitive)) { + containsAll = false; + break; + } + } + + if (containsAll) + searchIndexTable.insert(fileName, it.value()); + } +} + +void Reader::setIndexFile(const QString &namespaceName, const QString &attributes) +{ + QString extention = namespaceName + QLatin1String("@") + attributes; + indexFile = indexPath + QLatin1String("/indexdb40.") + extention; + documentFile = indexPath + QLatin1String("/indexdoc40.") + extention; +} + +bool Reader::splitSearchTerm(const QString &searchTerm, QStringList *terms, + QStringList *termSeq, QStringList *seqWords) +{ + QString term = searchTerm; + + term = term.simplified(); + term = term.replace(QLatin1String("\'"), QLatin1String("\"")); + term = term.replace(QLatin1String("`"), QLatin1String("\"")); + term = term.replace(QLatin1String("-"), QLatin1String(" ")); + term = term.replace(QRegExp(QLatin1String("\\s[\\S]?\\s")), QLatin1String(" ")); + + *terms = term.split(QLatin1Char(' ')); + QStringList::iterator it = terms->begin(); + for (; it != terms->end(); ++it) { + (*it) = (*it).simplified(); + (*it) = (*it).toLower(); + (*it) = (*it).replace(QLatin1String("\""), QLatin1String("")); + } + + if (term.contains(QLatin1Char('\"'))) { + if ((term.count(QLatin1Char('\"')))%2 == 0) { + int beg = 0; + int end = 0; + QString s; + beg = term.indexOf(QLatin1Char('\"'), beg); + while (beg != -1) { + beg++; + end = term.indexOf(QLatin1Char('\"'), beg); + s = term.mid(beg, end - beg); + s = s.toLower(); + s = s.simplified(); + if (s.contains(QLatin1Char('*'))) { + qWarning("Full Text Search, using a wildcard within phrases is not allowed."); + return false; + } + *seqWords += s.split(QLatin1Char(' ')); + *termSeq << s; + beg = term.indexOf(QLatin1Char('\"'), end + 1); + } + } else { + qWarning("Full Text Search, the closing quotation mark is missing."); + return false; + } + } + + return true; +} + +void Reader::searchInIndex(const QStringList &terms) +{ + foreach (const QString term, terms) { + QVector<Document> documents; + + for(IndexTable::ConstIterator it = searchIndexTable.begin(); + it != searchIndexTable.end(); ++it) { + EntryTable entryTable = it.value().first; + DocumentList documentList = it.value().second; + + if (term.contains(QLatin1Char('*'))) + documents = setupDummyTerm(getWildcardTerms(term, entryTable), entryTable); + else if (entryTable.value(term)) + documents = entryTable.value(term)->documents; + else + continue; + + if (!documents.isEmpty()) { + DocumentInfo info; + QString title, url; + QVector<DocumentInfo> documentsInfo; + foreach(const Document doc, documents) { + info.docNumber = doc.docNumber; + info.frequency = doc.frequency; + info.documentUrl = documentList.at(doc.docNumber).at(1); + info.documentTitle = documentList.at(doc.docNumber).at(0); + documentsInfo.append(info); + } + + bool found = false; + for(QList<TermInfo>::Iterator tit = termList.begin(); + tit != termList.end(); ++tit) { + TermInfo *t = &(*tit); + if(t->term == term) { + t->documents += documentsInfo; + t->frequency += documentsInfo.count(); + found = true; break; + } + } + if (!found) + termList.append(TermInfo(term, documentsInfo.count(), documentsInfo)); + } + } + } + qSort(termList); +} + +QVector<DocumentInfo> Reader::hits() +{ + QVector<DocumentInfo> documents; + if (!termList.count()) + return documents; + + documents = termList.takeFirst().documents; + for(QList<TermInfo>::Iterator it = termList.begin(); it != termList.end(); ++it) { + TermInfo *t = &(*it); + QVector<DocumentInfo> docs = t->documents; + for(QVector<DocumentInfo>::Iterator minDoc_it = documents.begin(); + minDoc_it != documents.end(); ) { + bool found = false; + for (QVector<DocumentInfo>::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 = documents.erase(minDoc_it); + else + ++minDoc_it; + } + } + + qSort(documents); + return documents; +} + +bool Reader::searchForPattern(const QStringList &patterns, const QStringList &words, + const QByteArray &data) +{ + if (data.isEmpty()) + return false; + + for(QHash<QString, PosEntry*>::ConstIterator mit = + miniIndex.begin(); mit != miniIndex.end(); ++mit) { + delete mit.value(); + } + miniIndex.clear(); + + wordNum = 3; + QStringList::ConstIterator cIt = words.begin(); + for ( ; cIt != words.end(); ++cIt ) + miniIndex.insert(*cIt, new PosEntry(0)); + + QTextStream s(data); + 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 ) + buildMiniIndex( 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 ) + buildMiniIndex( QString(str,i) ); + i = 0; + } + c = buf[++j]; + } + if ( i > 1 ) + buildMiniIndex( QString(str,i) ); + + 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 = miniIndex[ wordLst[0] ]->positions; + for ( int j = 1; j < (int)wordLst.count(); ++j ) { + b = miniIndex[ 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; +} + +QVector<Document> Reader::setupDummyTerm(const QStringList &terms, + const EntryTable &entryTable) +{ + QList<Term> termList; + for (QStringList::ConstIterator it = terms.begin(); it != terms.end(); ++it) { + if (entryTable.value(*it)) { + Entry *e = entryTable.value(*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; +} + +QStringList Reader::getWildcardTerms(const QString &term, + const EntryTable &entryTable) +{ + QStringList lst; + QStringList terms = split(term); + QStringList::Iterator iter; + + for(EntryTable::ConstIterator it = entryTable.begin(); + it != entryTable.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; +} + +void Reader::buildMiniIndex(const QString &string) +{ + if (miniIndex[string]) + miniIndex[string]->positions.append(wordNum); + ++wordNum; +} + +void Reader::reset() +{ + for(IndexTable::Iterator it = indexTable.begin(); + it != indexTable.end(); ++it) { + cleanupIndex(it.value().first); + it.value().second.clear(); + } +} + +void Reader::cleanupIndex(EntryTable &entryTable) +{ + for(EntryTable::ConstIterator it = + entryTable.begin(); it != entryTable.end(); ++it) { + delete it.value(); + } + + entryTable.clear(); +} + + +QHelpSearchIndexReader::QHelpSearchIndexReader() + : QThread() + , m_cancel(false) +{ + // nothing todo +} + +QHelpSearchIndexReader::~QHelpSearchIndexReader() +{ + mutex.lock(); + this->m_cancel = true; + waitCondition.wakeOne(); + mutex.unlock(); + + wait(); +} + +void QHelpSearchIndexReader::cancelSearching() +{ + mutex.lock(); + this->m_cancel = true; + mutex.unlock(); +} + +void QHelpSearchIndexReader::search(const QString &collectionFile, + const QString &indexFilesFolder, + const QList<QHelpSearchQuery> &queryList) +{ + QMutexLocker lock(&mutex); + + this->hitList.clear(); + this->m_cancel = false; + this->m_query = queryList; + this->m_collectionFile = collectionFile; + this->m_indexFilesFolder = indexFilesFolder; + + start(QThread::NormalPriority); +} + +int QHelpSearchIndexReader::hitsCount() const +{ + return hitList.count(); +} + +QHelpSearchEngine::SearchHit QHelpSearchIndexReader::hit(int index) const +{ + return hitList.at(index); +} + +void QHelpSearchIndexReader::run() +{ + mutex.lock(); + + if (m_cancel) { + mutex.unlock(); + return; + } + + const QList<QHelpSearchQuery> &queryList = this->m_query; + const QLatin1String key("DefaultSearchNamespaces"); + const QString collectionFile(this->m_collectionFile); + const QString indexPath = m_indexFilesFolder; + + mutex.unlock(); + + QString queryTerm; + foreach (const QHelpSearchQuery query, queryList) { + if (query.fieldName == QHelpSearchQuery::DEFAULT) { + queryTerm = query.wordList.at(0); + break; + } + } + + if (queryTerm.isEmpty()) + return; + + QHelpEngineCore engine(collectionFile, 0); + if (!engine.setupData()) + return; + + const QStringList registeredDocs = engine.registeredDocumentations(); + const QStringList indexedNamespaces = engine.customValue(key).toString(). + split(QLatin1String("|"), QString::SkipEmptyParts); + + emit searchingStarted(); + + // setup the reader + m_reader.setIndexPath(indexPath); + foreach(const QString namespaceName, registeredDocs) { + mutex.lock(); + if (m_cancel) { + mutex.unlock(); + searchingFinished(0); // TODO: check this ??? + return; + } + mutex.unlock(); + + const QList<QStringList> attributeSets = + engine.filterAttributeSets(namespaceName); + + foreach (QStringList attributes, attributeSets) { + // read all index files + m_reader.setIndexFile(namespaceName, attributes.join(QLatin1String("@"))); + if (!m_reader.readIndex()) { + qWarning("Full Text Search, could not read file for namespace: %s.", + namespaceName.toUtf8().constData()); + } + } + } + + // get the current filter attributes and minimize the index files table + m_reader.filterFilesForAttributes(engine.filterAttributes(engine.currentFilter())); + + hitList.clear(); + QStringList terms, termSeq, seqWords; + if (m_reader.initCheck() && // check if we could read anything + m_reader.splitSearchTerm(queryTerm, &terms, &termSeq, &seqWords) ) { + + // search for term(s) + m_reader.searchInIndex(terms); // TODO: should this be interruptible as well ??? + + QVector<DocumentInfo> hits = m_reader.hits(); + if (!hits.isEmpty()) { + if (termSeq.isEmpty()) { + foreach (const DocumentInfo docInfo, hits) { + mutex.lock(); + if (m_cancel) { + mutex.unlock(); + searchingFinished(0); // TODO: check this, speed issue while locking??? + return; + } + mutex.unlock(); + hitList.append(qMakePair(docInfo.documentTitle, docInfo.documentUrl)); + } + } else { + foreach (const DocumentInfo docInfo, hits) { + mutex.lock(); + if (m_cancel) { + mutex.unlock(); + searchingFinished(0); // TODO: check this, speed issue while locking??? + return; + } + mutex.unlock(); + + if (m_reader.searchForPattern(termSeq, seqWords, engine.fileData(docInfo.documentUrl))) // TODO: should this be interruptible as well ??? + hitList.append(qMakePair(docInfo.documentTitle, docInfo.documentUrl)); + } + } + } + } + + emit searchingFinished(hitList.count()); +} + + } // namespace std + } // namespace fulltextsearch +} // namespace qt + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpsearchindexreader_default_p.h b/tools/assistant/lib/qhelpsearchindexreader_default_p.h new file mode 100644 index 0000000..22480f7 --- /dev/null +++ b/tools/assistant/lib/qhelpsearchindexreader_default_p.h @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHINDEXREADERDEFAULT_H +#define QHELPSEARCHINDEXREADERDEFAULT_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhelpsearchindex_default_p.h" +#include "qhelpsearchengine.h" + +#include <QtCore/QHash> +#include <QtCore/QPair> +#include <QtCore/QList> +#include <QtCore/QMutex> +#include <QtCore/QString> +#include <QtCore/QThread> +#include <QtCore/QObject> +#include <QtCore/QVector> +#include <QtCore/QByteArray> +#include <QtCore/QStringList> +#include <QtCore/QWaitCondition> + +QT_BEGIN_NAMESPACE + +struct Entry; +struct PosEntry; + +namespace qt { + namespace fulltextsearch { + namespace std { + +class Reader +{ + typedef QList<QStringList> DocumentList; + typedef QHash<QString, Entry*> EntryTable; + typedef QPair<EntryTable, DocumentList> Index; + typedef QHash<QString, Index> IndexTable; + +public: + Reader(); + ~Reader(); + + bool readIndex(); + bool initCheck() const; + void setIndexPath(const QString &path); + void filterFilesForAttributes(const QStringList &attributes); + void setIndexFile(const QString &namespaceName, const QString &attributes); + bool splitSearchTerm(const QString &searchTerm, QStringList *terms, + QStringList *termSeq, QStringList *seqWords); + + void searchInIndex(const QStringList &terms); + QVector<DocumentInfo> hits(); + bool searchForPattern(const QStringList &patterns, + const QStringList &words, const QByteArray &data); + +private: + QVector<Document> setupDummyTerm(const QStringList &terms, const EntryTable &entryTable); + QStringList getWildcardTerms(const QString &term, const EntryTable &entryTable); + void buildMiniIndex(const QString &string); + void reset(); + void cleanupIndex(EntryTable &entryTable); + +private: + uint wordNum; + QString indexPath; + QString indexFile; + QString documentFile; + + IndexTable indexTable; + QList<TermInfo> termList; + IndexTable searchIndexTable; + QHash<QString, PosEntry*> miniIndex; +}; + + +class QHelpSearchIndexReader : public QThread +{ + Q_OBJECT + +public: + QHelpSearchIndexReader(); + ~QHelpSearchIndexReader(); + + void cancelSearching(); + void search(const QString &collectionFile, + const QString &indexFilesFolder, + const QList<QHelpSearchQuery> &queryList); + + int hitsCount() const; + QHelpSearchEngine::SearchHit hit(int index) const; + +signals: + void searchingStarted(); + void searchingFinished(int hits); + +private: + void run(); + +private: + QMutex mutex; + Reader m_reader; + QWaitCondition waitCondition; + QList<QHelpSearchEngine::SearchHit> hitList; + + bool m_cancel; + QList<QHelpSearchQuery> m_query; + QString m_collectionFile; + QString m_indexFilesFolder; +}; + + } // namespace std + } // namespace fulltextsearch +} // namespace qt + +QT_END_NAMESPACE + +#endif // QHELPSEARCHINDEXREADERDEFAULT_H diff --git a/tools/assistant/lib/qhelpsearchindexwriter_clucene.cpp b/tools/assistant/lib/qhelpsearchindexwriter_clucene.cpp new file mode 100644 index 0000000..e53bbae --- /dev/null +++ b/tools/assistant/lib/qhelpsearchindexwriter_clucene.cpp @@ -0,0 +1,481 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpenginecore.h" +#include "qhelp_global.h" +#include "fulltextsearch/qhits_p.h" +#include "fulltextsearch/qquery_p.h" +#include "fulltextsearch/qanalyzer_p.h" +#include "fulltextsearch/qdocument_p.h" +#include "fulltextsearch/qsearchable_p.h" +#include "fulltextsearch/qindexreader_p.h" +#include "fulltextsearch/qindexwriter_p.h" +#include "qhelpsearchindexwriter_clucene_p.h" + +#include <QtCore/QDir> +#include <QtCore/QString> +#include <QtCore/QFileInfo> +#include <QtCore/QTextCodec> +#include <QtCore/QTextStream> + +#include <QtNetwork/QLocalSocket> +#include <QtNetwork/QLocalServer> + +QT_BEGIN_NAMESPACE + +namespace qt { + namespace fulltextsearch { + namespace clucene { + +class DocumentHelper +{ +public: + DocumentHelper(const QString& fileName, const QByteArray &data) + : fileName(fileName) , data(readData(data)) {} + ~DocumentHelper() {} + + bool addFieldsToDocument(QCLuceneDocument *document, + const QString &namespaceName, const QString &attributes = QString()) + { + if (!document) + return false; + + if(!data.isEmpty()) { + QString parsedData = parseData(); + QString parsedTitle = QHelpGlobal::documentTitle(data); + + if(!parsedData.isEmpty()) { + document->add(new QCLuceneField(QLatin1String("content"), + parsedData,QCLuceneField::INDEX_TOKENIZED)); + document->add(new QCLuceneField(QLatin1String("path"), fileName, + QCLuceneField::STORE_YES | QCLuceneField::INDEX_UNTOKENIZED)); + document->add(new QCLuceneField(QLatin1String("title"), parsedTitle, + QCLuceneField::STORE_YES | QCLuceneField::INDEX_UNTOKENIZED)); + document->add(new QCLuceneField(QLatin1String("titleTokenized"), parsedTitle, + QCLuceneField::STORE_YES | QCLuceneField::INDEX_TOKENIZED)); + document->add(new QCLuceneField(QLatin1String("namespace"), namespaceName, + QCLuceneField::STORE_YES | QCLuceneField::INDEX_UNTOKENIZED)); + document->add(new QCLuceneField(QLatin1String("attribute"), attributes, + QCLuceneField::STORE_YES | QCLuceneField::INDEX_TOKENIZED)); + return true; + } + } + + return false; + } + +private: + QString readData(const QByteArray &data) + { + QTextStream textStream(data); + QByteArray charSet = QHelpGlobal::charsetFromData(data).toLatin1(); + textStream.setCodec(QTextCodec::codecForName(charSet.constData())); + + QString stream = textStream.readAll(); + if (stream.isNull() || stream.isEmpty()) + return QString(); + + return stream; + } + + QString parseData() const + { + const int length = data.length(); + const QChar *buf = data.unicode(); + + QString parsedContent; + parsedContent.reserve(length); + + bool valid = true; + int j = 0, count = 0; + + QChar c; + while (j < length) { + c = buf[j++]; + if (c == QLatin1Char('<') || c == QLatin1Char('&')) { + if (count > 1) + parsedContent.append(QLatin1Char(' ')); + count = 0; + valid = false; + continue; + } + if ((c == QLatin1Char('>') || c == QLatin1Char(';')) && !valid) { + valid = true; + continue; + } + if (!valid) + continue; + + if (c.isLetterOrNumber() || c.isPrint()) { + ++count; + parsedContent.append(c.toLower()); + } else { + if (count > 1) + parsedContent.append(QLatin1Char(' ')); + count = 0; + } + } + + return parsedContent; + } + +private: + QString fileName; + QString data; +}; + + +QHelpSearchIndexWriter::QHelpSearchIndexWriter() + : QThread(0) + , m_cancel(false) +{ + // nothing todo +} + +QHelpSearchIndexWriter::~QHelpSearchIndexWriter() +{ + mutex.lock(); + this->m_cancel = true; + waitCondition.wakeOne(); + mutex.unlock(); + + wait(); +} + +void QHelpSearchIndexWriter::cancelIndexing() +{ + mutex.lock(); + this->m_cancel = true; + mutex.unlock(); +} + +void QHelpSearchIndexWriter::updateIndex(const QString &collectionFile, + const QString &indexFilesFolder, bool reindex) +{ + mutex.lock(); + this->m_cancel = false; + this->m_reindex = reindex; + this->m_collectionFile = collectionFile; + this->m_indexFilesFolder = indexFilesFolder; + mutex.unlock(); + + start(QThread::NormalPriority); +} + +void QHelpSearchIndexWriter::optimizeIndex() +{ + if (QCLuceneIndexReader::indexExists(m_indexFilesFolder)) { + if (QCLuceneIndexReader::isLocked(m_indexFilesFolder)) + return; + + QCLuceneStandardAnalyzer analyzer; + QCLuceneIndexWriter writer(m_indexFilesFolder, analyzer, false); + writer.optimize(); + writer.close(); + } +} + +void QHelpSearchIndexWriter::run() +{ + QMutexLocker mutexLocker(&mutex); + + if (m_cancel) + return; + + const bool reindex = this->m_reindex; + const QString collectionFile(this->m_collectionFile); + + mutexLocker.unlock(); + + QHelpEngineCore engine(collectionFile, 0); + if (!engine.setupData()) + return; + + const QLatin1String key("CluceneIndexedNamespaces"); + if (reindex) + engine.setCustomValue(key, QLatin1String("")); + + QMap<QString, QDateTime> indexMap; + const QLatin1String oldKey("CluceneSearchNamespaces"); + if (!engine.customValue(oldKey, QString()).isNull()) { + // old style qhc file < 4.4.2, need to convert... + const QStringList indexedNamespaces = engine.customValue(oldKey). + toString().split(QLatin1String("|"), QString::SkipEmptyParts); + foreach (const QString& nameSpace, indexedNamespaces) + indexMap.insert(nameSpace, QDateTime()); + engine.removeCustomValue(oldKey); + } else { + QDataStream dataStream(engine.customValue(key).toByteArray()); + dataStream >> indexMap; + } + + QString indexPath = m_indexFilesFolder; + + QFileInfo fInfo(indexPath); + if (fInfo.exists() && !fInfo.isWritable()) { + qWarning("Full Text Search, could not create index (missing permissions)."); + return; + } + + emit indexingStarted(); + + QCLuceneIndexWriter *writer = 0; + QCLuceneStandardAnalyzer analyzer; + const QStringList registeredDocs = engine.registeredDocumentations(); + + QLocalSocket localSocket; + localSocket.connectToServer(QString(QLatin1String("QtAssistant%1")) + .arg(QLatin1String(QT_VERSION_STR))); + + QLocalServer localServer; + bool otherInstancesRunning = true; + if (!localSocket.waitForConnected()) { + otherInstancesRunning = false; + localServer.listen(QString(QLatin1String("QtAssistant%1")) + .arg(QLatin1String(QT_VERSION_STR))); + } + +#if !defined(QT_NO_EXCEPTIONS) + try { +#endif + // check if it's locked, and if the other instance is running + if (!otherInstancesRunning && QCLuceneIndexReader::isLocked(indexPath)) + QCLuceneIndexReader::unlock(indexPath); + + if (QCLuceneIndexReader::isLocked(indexPath)) { + // poll unless indexing finished to fake progress + while (QCLuceneIndexReader::isLocked(indexPath)) { + mutexLocker.relock(); + if (m_cancel) + break; + mutexLocker.unlock(); + this->sleep(1); + } + emit indexingFinished(); + return; + } + + if (QCLuceneIndexReader::indexExists(indexPath) && !reindex) { + foreach(const QString& namespaceName, registeredDocs) { + mutexLocker.relock(); + if (m_cancel) { + emit indexingFinished(); + return; + } + mutexLocker.unlock(); + + if (!indexMap.contains(namespaceName)) { + // make sure we remove some partly indexed stuff + removeDocuments(indexPath, namespaceName); + } else { + QString path = engine.documentationFileName(namespaceName); + if (indexMap.value(namespaceName) < QFileInfo(path).lastModified()) { + // make sure we remove some outdated indexed stuff + indexMap.remove(namespaceName); + removeDocuments(indexPath, namespaceName); + } + + 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)); + QCLuceneIndexSearcher indexSearcher(indexPath); + QCLuceneHits hits = indexSearcher.search(query); + if (hits.length() <= 0) + indexMap.remove(namespaceName); + } + } + } + writer = new QCLuceneIndexWriter(indexPath, analyzer, false); + } else { + indexMap.clear(); + writer = new QCLuceneIndexWriter(indexPath, analyzer, true); + } +#if !defined(QT_NO_EXCEPTIONS) + } catch (...) { + qWarning("Full Text Search, could not create index writer."); + return; + } +#endif + + writer->setMergeFactor(100); + writer->setMinMergeDocs(1000); + writer->setMaxFieldLength(QCLuceneIndexWriter::DEFAULT_MAX_FIELD_LENGTH); + + QStringList namespaces; + foreach(const QString& namespaceName, registeredDocs) { + mutexLocker.relock(); + if (m_cancel) { + writer->close(); + delete writer; + emit indexingFinished(); + return; + } + mutexLocker.unlock(); + + namespaces.append(namespaceName); + if (indexMap.contains(namespaceName)) + continue; + + const QList<QStringList> attributeSets = + engine.filterAttributeSets(namespaceName); + + if (attributeSets.isEmpty()) { + const QList<QUrl> docFiles = indexableFiles(&engine, namespaceName, + QStringList()); + if (!addDocuments(docFiles, engine, QStringList(), namespaceName, + writer, analyzer)) + break; + } else { + bool bail = false; + foreach (const QStringList& attributes, attributeSets) { + const QList<QUrl> docFiles = indexableFiles(&engine, + namespaceName, attributes); + if (!addDocuments(docFiles, engine, attributes, namespaceName, + writer, analyzer)) { + bail = true; + break; + } + } + if (bail) + break; + } + + mutexLocker.relock(); + if (!m_cancel) { + QString path(engine.documentationFileName(namespaceName)); + indexMap.insert(namespaceName, QFileInfo(path).lastModified()); + writeIndexMap(engine, indexMap); + } + mutexLocker.unlock(); + } + + writer->close(); + delete writer; + + mutexLocker.relock(); + if (!m_cancel) { + mutexLocker.unlock(); + + QStringList indexedNamespaces = indexMap.keys(); + foreach(const QString& namespaceName, indexedNamespaces) { + mutexLocker.relock(); + if (m_cancel) + break; + mutexLocker.unlock(); + + if (!namespaces.contains(namespaceName)) { + indexMap.remove(namespaceName); + writeIndexMap(engine, indexMap); + removeDocuments(indexPath, namespaceName); + } + } + } + emit indexingFinished(); +} + +bool QHelpSearchIndexWriter::addDocuments(const QList<QUrl> docFiles, + const QHelpEngineCore &engine, const QStringList &attributes, + const QString &namespaceName, QCLuceneIndexWriter *writer, + QCLuceneAnalyzer &analyzer) +{ + QMutexLocker locker(&mutex); + const QString attrList = attributes.join(QLatin1String(" ")); + + locker.unlock(); + foreach(const QUrl& url, docFiles) { + QCLuceneDocument document; + DocumentHelper helper(url.toString(), engine.fileData(url)); + if (helper.addFieldsToDocument(&document, namespaceName, attrList)) + writer->addDocument(document, analyzer); + + locker.relock(); + if (m_cancel) + return false; + locker.unlock(); + } + + return true; +} + +void QHelpSearchIndexWriter::removeDocuments(const QString &indexPath, + const QString &namespaceName) +{ + if (namespaceName.isEmpty() || QCLuceneIndexReader::isLocked(indexPath)) + return; + + QCLuceneIndexReader reader = QCLuceneIndexReader::open(indexPath); + reader.deleteDocuments(QCLuceneTerm(QLatin1String("namespace"), + namespaceName)); + + reader.close(); +} + +bool QHelpSearchIndexWriter::writeIndexMap(QHelpEngineCore& engine, + const QMap<QString, QDateTime>& indexMap) +{ + QByteArray bArray; + + QDataStream data(&bArray, QIODevice::ReadWrite); + data << indexMap; + + return engine.setCustomValue(QLatin1String("CluceneIndexedNamespaces"), + bArray); +} + +QList<QUrl> QHelpSearchIndexWriter::indexableFiles(QHelpEngineCore *helpEngine, + const QString &namespaceName, const QStringList &attributes) const +{ + QList<QUrl> docFiles = helpEngine->files(namespaceName, attributes, + QLatin1String("html")); + docFiles += helpEngine->files(namespaceName, attributes, QLatin1String("htm")); + docFiles += helpEngine->files(namespaceName, attributes, QLatin1String("txt")); + + return docFiles; +} + + + } // namespace clucene + } // namespace fulltextsearch +} // namespace qt + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpsearchindexwriter_clucene_p.h b/tools/assistant/lib/qhelpsearchindexwriter_clucene_p.h new file mode 100644 index 0000000..55c852b --- /dev/null +++ b/tools/assistant/lib/qhelpsearchindexwriter_clucene_p.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHINDEXWRITERCLUCENE_H +#define QHELPSEARCHINDEXWRITERCLUCENE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhelpenginecore.h" +#include "fulltextsearch/qanalyzer_p.h" + +#include <QtCore/QUrl> +#include <QtCore/QThread> +#include <QtCore/QMutex> +#include <QtCore/QObject> +#include <QtCore/QString> +#include <QtCore/QDateTime> +#include <QtCore/QStringList> +#include <QtCore/QWaitCondition> + +QT_BEGIN_NAMESPACE + +class QCLuceneIndexWriter; + +namespace qt { + namespace fulltextsearch { + namespace clucene { + +class QHelpSearchIndexWriter : public QThread +{ + Q_OBJECT + +public: + QHelpSearchIndexWriter(); + ~QHelpSearchIndexWriter(); + + void cancelIndexing(); + void updateIndex(const QString &collectionFile, + const QString &indexFilesFolder, bool reindex); + void optimizeIndex(); + +signals: + void indexingStarted(); + void indexingFinished(); + +private: + void run(); + + bool addDocuments(const QList<QUrl> docFiles, const QHelpEngineCore &engine, + const QStringList &attributes, const QString &namespaceName, + QCLuceneIndexWriter *writer, QCLuceneAnalyzer &analyzer); + void removeDocuments(const QString &indexPath, const QString &namespaceName); + + bool writeIndexMap(QHelpEngineCore& engine, + const QMap<QString, QDateTime>& indexMap); + + QList<QUrl> indexableFiles(QHelpEngineCore *helpEngine, + const QString &namespaceName, const QStringList &attributes) const; + +private: + QMutex mutex; + QWaitCondition waitCondition; + + bool m_cancel; + bool m_reindex; + QString m_collectionFile; + QString m_indexFilesFolder; +}; + + } // namespace clucene + } // namespace fulltextsearch +} // namespace clucene + +QT_END_NAMESPACE + +#endif // QHELPSEARCHINDEXWRITERCLUCENE_H diff --git a/tools/assistant/lib/qhelpsearchindexwriter_default.cpp b/tools/assistant/lib/qhelpsearchindexwriter_default.cpp new file mode 100644 index 0000000..d55b984 --- /dev/null +++ b/tools/assistant/lib/qhelpsearchindexwriter_default.cpp @@ -0,0 +1,385 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpsearchindexwriter_default_p.h" +#include "qhelp_global.h" +#include "qhelpenginecore.h" + +#include <QtCore/QDir> +#include <QtCore/QSet> +#include <QtCore/QUrl> +#include <QtCore/QFile> +#include <QtCore/QRegExp> +#include <QtCore/QVariant> +#include <QtCore/QFileInfo> +#include <QtCore/QTextCodec> +#include <QtCore/QTextStream> + +QT_BEGIN_NAMESPACE + +namespace qt { + namespace fulltextsearch { + namespace std { + +Writer::Writer(const QString &path) + : indexPath(path) + , indexFile(QString()) + , documentFile(QString()) +{ + // nothing todo +} + +Writer::~Writer() +{ + reset(); +} + +void Writer::reset() +{ + for(QHash<QString, Entry*>::ConstIterator it = + index.begin(); it != index.end(); ++it) { + delete it.value(); + } + + index.clear(); + documentList.clear(); +} + +bool Writer::writeIndex() const +{ + bool status; + QFile idxFile(indexFile); + if (!(status = idxFile.open(QFile::WriteOnly))) + return status; + + QDataStream indexStream(&idxFile); + for(QHash<QString, Entry*>::ConstIterator it = + index.begin(); it != index.end(); ++it) { + indexStream << it.key(); + indexStream << it.value()->documents.count(); + indexStream << it.value()->documents; + } + idxFile.close(); + + QFile docFile(documentFile); + if (!(status = docFile.open(QFile::WriteOnly))) + return status; + + QDataStream docStream(&docFile); + foreach(const QStringList list, documentList) { + docStream << list.at(0); + docStream << list.at(1); + } + docFile.close(); + + return status; +} + +void Writer::removeIndex() const +{ + QFile idxFile(indexFile); + if (idxFile.exists()) + idxFile.remove(); + + QFile docFile(documentFile); + if (docFile.exists()) + docFile.remove(); +} + +void Writer::setIndexFile(const QString &namespaceName, const QString &attributes) +{ + QString extention = namespaceName + QLatin1String("@") + attributes; + indexFile = indexPath + QLatin1String("/indexdb40.") + extention; + documentFile = indexPath + QLatin1String("/indexdoc40.") + extention; +} + +void Writer::insertInIndex(const QString &string, int docNum) +{ + if (string == QLatin1String("amp") || string == QLatin1String("nbsp")) + return; + + Entry *entry = 0; + if (index.count()) + entry = index[string]; + + if (entry) { + if (entry->documents.last().docNumber != docNum) + entry->documents.append(Document(docNum, 1)); + else + entry->documents.last().frequency++; + } else { + index.insert(string, new Entry(docNum)); + } +} + +void Writer::insertInDocumentList(const QString &title, const QString &url) +{ + documentList.append(QStringList(title) << url); +} + + +QHelpSearchIndexWriter::QHelpSearchIndexWriter() + : QThread() + , m_cancel(false) +{ + // nothing todo +} + +QHelpSearchIndexWriter::~QHelpSearchIndexWriter() +{ + mutex.lock(); + this->m_cancel = true; + waitCondition.wakeOne(); + mutex.unlock(); + + wait(); +} + +void QHelpSearchIndexWriter::cancelIndexing() +{ + mutex.lock(); + this->m_cancel = true; + mutex.unlock(); +} + +void QHelpSearchIndexWriter::updateIndex(const QString &collectionFile, + const QString &indexFilesFolder, + bool reindex) +{ + QMutexLocker lock(&mutex); + + this->m_cancel = false; + this->m_reindex = reindex; + this->m_collectionFile = collectionFile; + this->m_indexFilesFolder = indexFilesFolder; + + start(QThread::NormalPriority); +} + +void QHelpSearchIndexWriter::run() +{ + mutex.lock(); + + if (m_cancel) { + mutex.unlock(); + return; + } + + const bool reindex(this->m_reindex); + const QLatin1String key("DefaultSearchNamespaces"); + const QString collectionFile(this->m_collectionFile); + const QString indexPath = m_indexFilesFolder; + + mutex.unlock(); + + QHelpEngineCore engine(collectionFile, 0); + if (!engine.setupData()) + return; + + if (reindex) + engine.setCustomValue(key, QLatin1String("")); + + const QStringList registeredDocs = engine.registeredDocumentations(); + const QStringList indexedNamespaces = engine.customValue(key).toString(). + split(QLatin1String("|"), QString::SkipEmptyParts); + + emit indexingStarted(); + + QStringList namespaces; + Writer writer(indexPath); + foreach(const QString namespaceName, registeredDocs) { + mutex.lock(); + if (m_cancel) { + mutex.unlock(); + return; + } + mutex.unlock(); + + // if indexed, continue + namespaces.append(namespaceName); + if (indexedNamespaces.contains(namespaceName)) + continue; + + const QList<QStringList> attributeSets = + engine.filterAttributeSets(namespaceName); + + foreach (QStringList attributes, attributeSets) { + // cleanup maybe old or unfinished files + writer.setIndexFile(namespaceName, attributes.join(QLatin1String("@"))); + writer.removeIndex(); + + QSet<QString> documentsSet; + const QList<QUrl> docFiles = engine.files(namespaceName, attributes); + foreach(QUrl url, docFiles) { + if (m_cancel) + return; + + // get rid of duplicated files + if (url.hasFragment()) + url.setFragment(QString()); + + QString s = url.toString(); + if (s.endsWith(QLatin1String(".html")) + || s.endsWith(QLatin1String(".htm")) + || s.endsWith(QLatin1String(".txt"))) + documentsSet.insert(s); + } + + int docNum = 0; + const QStringList documentsList(documentsSet.toList()); + foreach(const QString url, documentsList) { + if (m_cancel) + return; + + QByteArray data(engine.fileData(url)); + if (data.isEmpty()) + continue; + + QTextStream s(data); + QString en = QHelpGlobal::charsetFromData(data); + s.setCodec(QTextCodec::codecForName(en.toLatin1().constData())); + + QString text = s.readAll(); + if (text.isNull()) + continue; + + QString title = QHelpGlobal::documentTitle(text); + + int j = 0; + int i = 0; + bool valid = true; + const QChar *buf = text.unicode(); + QChar str[64]; + QChar c = buf[0]; + + while ( j < text.length() ) { + if (m_cancel) + return; + + if ( c == QLatin1Char('<') || c == QLatin1Char('&') ) { + valid = false; + if ( i > 1 ) + writer.insertInIndex(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 ) + writer.insertInIndex(QString(str,i), docNum); + i = 0; + } + c = buf[++j]; + } + if ( i > 1 ) + writer.insertInIndex(QString(str,i), docNum); + + docNum++; + writer.insertInDocumentList(title, url); + } + + if (writer.writeIndex()) { + engine.setCustomValue(key, addNamespace( + engine.customValue(key).toString(), namespaceName)); + } + + writer.reset(); + } + } + + QStringListIterator qsli(indexedNamespaces); + while (qsli.hasNext()) { + const QString namespaceName = qsli.next(); + if (namespaces.contains(namespaceName)) + continue; + + const QList<QStringList> attributeSets = + engine.filterAttributeSets(namespaceName); + + foreach (QStringList attributes, attributeSets) { + writer.setIndexFile(namespaceName, attributes.join(QLatin1String("@"))); + writer.removeIndex(); + } + + engine.setCustomValue(key, removeNamespace( + engine.customValue(key).toString(), namespaceName)); + } + + emit indexingFinished(); +} + +QString QHelpSearchIndexWriter::addNamespace(const QString namespaces, + const QString &namespaceName) +{ + QString value = namespaces; + if (!value.contains(namespaceName)) + value.append(namespaceName).append(QLatin1String("|")); + + return value; +} + +QString QHelpSearchIndexWriter::removeNamespace(const QString namespaces, + const QString &namespaceName) +{ + QString value = namespaces; + if (value.contains(namespaceName)) + value.remove(namespaceName + QLatin1String("|")); + + return value; +} + + } // namespace std + } // namespace fulltextsearch +} // namespace qt + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpsearchindexwriter_default_p.h b/tools/assistant/lib/qhelpsearchindexwriter_default_p.h new file mode 100644 index 0000000..015eb5a --- /dev/null +++ b/tools/assistant/lib/qhelpsearchindexwriter_default_p.h @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHINDEXWRITERDEFAULT_H +#define QHELPSEARCHINDEXWRITERDEFAULT_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhelpsearchindex_default_p.h" + +#include <QtCore/QHash> +#include <QtCore/QMutex> +#include <QtCore/QObject> +#include <QtCore/QString> +#include <QtCore/QThread> +#include <QtCore/QStringList> +#include <QtCore/QWaitCondition> + +QT_BEGIN_NAMESPACE + +namespace qt { + namespace fulltextsearch { + namespace std { + +class Writer +{ +public: + Writer(const QString &path); + ~Writer(); + + void reset(); + bool writeIndex() const; + void removeIndex() const; + void setIndexFile(const QString &namespaceName, const QString &attributes); + void insertInIndex(const QString &string, int docNum); + void insertInDocumentList(const QString &title, const QString &url); + +private: + QString indexPath; + QString indexFile; + QString documentFile; + + QHash<QString, Entry*> index; + QList<QStringList> documentList; +}; + + +class QHelpSearchIndexWriter : public QThread +{ + Q_OBJECT + +public: + QHelpSearchIndexWriter(); + ~QHelpSearchIndexWriter(); + + void cancelIndexing(); + void updateIndex(const QString &collectionFile, + const QString &indexFilesFolder, bool reindex); + +signals: + void indexingStarted(); + void indexingFinished(); + +private: + void run(); + QString addNamespace(const QString namespaces, const QString &namespaceName); + QString removeNamespace(const QString namespaces, const QString &namespaceName); + +private: + QMutex mutex; + QWaitCondition waitCondition; + + bool m_cancel; + bool m_reindex; + QString m_collectionFile; + QString m_indexFilesFolder; +}; + + } // namespace std + } // namespace fulltextsearch +} // namespace qt + +QT_END_NAMESPACE + +#endif // QHELPSEARCHINDEXWRITERDEFAULT_H diff --git a/tools/assistant/lib/qhelpsearchquerywidget.cpp b/tools/assistant/lib/qhelpsearchquerywidget.cpp new file mode 100644 index 0000000..c018ffc --- /dev/null +++ b/tools/assistant/lib/qhelpsearchquerywidget.cpp @@ -0,0 +1,353 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpsearchquerywidget.h" + +#include <QtCore/QDebug> + +#include <QtCore/QObject> +#include <QtCore/QStringList> + +#include <QtGui/QLabel> +#include <QtGui/QLayout> +#include <QtGui/QLineEdit> +#include <QtGui/QFocusEvent> +#include <QtGui/QPushButton> +#include <QtGui/QToolButton> + +QT_BEGIN_NAMESPACE + +class QHelpSearchQueryWidgetPrivate : public QObject +{ + Q_OBJECT + +private: + QHelpSearchQueryWidgetPrivate() + : QObject() + { + searchButton = 0; + advancedSearchWidget = 0; + showHideAdvancedSearchButton = 0; + defaultQuery = 0; + exactQuery = 0; + similarQuery = 0; + withoutQuery = 0; + allQuery = 0; + atLeastQuery = 0; + } + + ~QHelpSearchQueryWidgetPrivate() + { + // nothing todo + } + + 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 realy 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; + QString phrase; + QStringList wordList; + QString searchTerm = query; + + for (int i = 0; i < searchTerm.length(); ++i) { + if (searchTerm[i] == QLatin1Char('\"') && !s) { + s = true; + phrase = searchTerm[i]; + continue; + } + if (searchTerm[i] != QLatin1Char('\"') && s) + phrase += searchTerm[i]; + if (searchTerm[i] == QLatin1Char('\"') && s) { + s = false; + phrase += searchTerm[i]; + wordList.append(phrase); + searchTerm.remove(phrase); + } + } + if (s) + searchTerm.replace(phrase, phrase.mid(1)); + + const QRegExp exp(QLatin1String("\\s+")); + wordList += searchTerm.split(exp, QString::SkipEmptyParts); + return wordList; + } + +private slots: + void showHideAdvancedSearch() + { + bool hidden = advancedSearchWidget->isHidden(); + if (hidden) { + advancedSearchWidget->show(); + showHideAdvancedSearchButton->setText((QLatin1String("-"))); + } else { + advancedSearchWidget->hide(); + showHideAdvancedSearchButton->setText((QLatin1String("+"))); + } + + defaultQuery->setEnabled(!hidden); + } + +private: + friend class QHelpSearchQueryWidget; + + QPushButton *searchButton; + QWidget* advancedSearchWidget; + QToolButton *showHideAdvancedSearchButton; + QLineEdit *defaultQuery; + QLineEdit *exactQuery; + QLineEdit *similarQuery; + QLineEdit *withoutQuery; + QLineEdit *allQuery; + QLineEdit *atLeastQuery; +}; + +#include "qhelpsearchquerywidget.moc" + + +/*! + \class QHelpSearchQueryWidget + \since 4.4 + \inmodule QtHelp + \brief The QHelpSearchQueryWidget class provides a simple line edit or + an advanced widget to enable the user to input a search term in a + standardized input mask. +*/ + +/*! + \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. +*/ + +/*! + Constructs a new search query widget with the given \a parent. +*/ +QHelpSearchQueryWidget::QHelpSearchQueryWidget(QWidget *parent) + : QWidget(parent) +{ + d = new QHelpSearchQueryWidgetPrivate(); + + QVBoxLayout *vLayout = new QVBoxLayout(this); + vLayout->setMargin(0); + + QHBoxLayout* hBoxLayout = new QHBoxLayout(); + QLabel *label = new QLabel(tr("Search for:"), this); + d->defaultQuery = new QLineEdit(this); + d->searchButton = new QPushButton(tr("Search"), this); + hBoxLayout->addWidget(label); + hBoxLayout->addWidget(d->defaultQuery); + hBoxLayout->addWidget(d->searchButton); + + vLayout->addLayout(hBoxLayout); + + connect(d->searchButton, SIGNAL(clicked()), this, SIGNAL(search())); + connect(d->defaultQuery, SIGNAL(returnPressed()), this, SIGNAL(search())); + +#if defined(QT_CLUCENE_SUPPORT) + hBoxLayout = new QHBoxLayout(); + d->showHideAdvancedSearchButton = new QToolButton(this); + d->showHideAdvancedSearchButton->setText(QLatin1String("+")); + d->showHideAdvancedSearchButton->setMinimumSize(25, 20); + + label = new QLabel(tr("Advanced search"), this); + QSizePolicy sizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); + sizePolicy.setHeightForWidth(label->sizePolicy().hasHeightForWidth()); + label->setSizePolicy(sizePolicy); + + QFrame* hLine = new QFrame(this); + hLine->setFrameStyle(QFrame::HLine); + hBoxLayout->addWidget(d->showHideAdvancedSearchButton); + hBoxLayout->addWidget(label); + hBoxLayout->addWidget(hLine); + + vLayout->addLayout(hBoxLayout); + + // setup advanced search layout + d->advancedSearchWidget = new QWidget(this); + QGridLayout *gLayout = new QGridLayout(d->advancedSearchWidget); + gLayout->setMargin(0); + + label = new QLabel(tr("words <B>similar</B> to:"), this); + gLayout->addWidget(label, 0, 0); + d->similarQuery = new QLineEdit(this); + gLayout->addWidget(d->similarQuery, 0, 1); + + label = new QLabel(tr("<B>without</B> the words:"), this); + gLayout->addWidget(label, 1, 0); + d->withoutQuery = new QLineEdit(this); + gLayout->addWidget(d->withoutQuery, 1, 1); + + label = new QLabel(tr("with <B>exact phrase</B>:"), this); + gLayout->addWidget(label, 2, 0); + d->exactQuery = new QLineEdit(this); + gLayout->addWidget(d->exactQuery, 2, 1); + + label = new QLabel(tr("with <B>all</B> of the words:"), this); + gLayout->addWidget(label, 3, 0); + d->allQuery = new QLineEdit(this); + gLayout->addWidget(d->allQuery, 3, 1); + + label = new QLabel(tr("with <B>at least one</B> of the words:"), this); + gLayout->addWidget(label, 4, 0); + d->atLeastQuery = new QLineEdit(this); + gLayout->addWidget(d->atLeastQuery, 4, 1); + + vLayout->addWidget(d->advancedSearchWidget); + d->advancedSearchWidget->hide(); + + connect(d->exactQuery, SIGNAL(returnPressed()), this, SIGNAL(search())); + connect(d->similarQuery, SIGNAL(returnPressed()), this, SIGNAL(search())); + connect(d->withoutQuery, SIGNAL(returnPressed()), this, SIGNAL(search())); + connect(d->allQuery, SIGNAL(returnPressed()), this, SIGNAL(search())); + connect(d->atLeastQuery, SIGNAL(returnPressed()), this, SIGNAL(search())); + connect(d->showHideAdvancedSearchButton, SIGNAL(clicked()), + d, SLOT(showHideAdvancedSearch())); +#endif +} + +/*! + Destroys the search query widget. +*/ +QHelpSearchQueryWidget::~QHelpSearchQueryWidget() +{ + delete d; +} + +/*! + Returns a list of querys to use in combination with the search engines + search(QList<QHelpSearchQuery> &query) function. +*/ +QList<QHelpSearchQuery> QHelpSearchQueryWidget::query() const +{ +#if !defined(QT_CLUCENE_SUPPORT) + QList<QHelpSearchQuery> queryList; + queryList.append(QHelpSearchQuery(QHelpSearchQuery::DEFAULT, + QStringList(d->defaultQuery->text()))); + + return queryList; +#else + QList<QHelpSearchQuery> queryList; + if (d->defaultQuery->isEnabled()) { + queryList.append(QHelpSearchQuery(QHelpSearchQuery::DEFAULT, + d->buildTermList(d->escapeString(d->defaultQuery->text())))); + } else { + const QRegExp exp(QLatin1String("\\s+")); + QStringList lst = d->similarQuery->text().split(exp, QString::SkipEmptyParts); + if (!lst.isEmpty()) { + QStringList fuzzy; + foreach (const QString term, lst) + fuzzy += d->buildTermList(d->escapeString(term)); + queryList.append(QHelpSearchQuery(QHelpSearchQuery::FUZZY, fuzzy)); + } + + lst = d->withoutQuery->text().split(exp, QString::SkipEmptyParts); + if (!lst.isEmpty()) { + QStringList without; + foreach (const QString term, lst) + without.append(d->escapeString(term)); + queryList.append(QHelpSearchQuery(QHelpSearchQuery::WITHOUT, without)); + } + + if (!d->exactQuery->text().isEmpty()) { + QString phrase = d->exactQuery->text().remove(QLatin1Char('\"')); + phrase = d->escapeString(phrase.simplified()); + queryList.append(QHelpSearchQuery(QHelpSearchQuery::PHRASE, QStringList(phrase))); + } + + lst = d->allQuery->text().split(exp, QString::SkipEmptyParts); + if (!lst.isEmpty()) { + QStringList all; + foreach (const QString term, lst) + all.append(d->escapeString(term)); + queryList.append(QHelpSearchQuery(QHelpSearchQuery::ALL, all)); + } + + lst = d->atLeastQuery->text().split(exp, QString::SkipEmptyParts); + if (!lst.isEmpty()) { + QStringList atLeast; + foreach (const QString term, lst) + atLeast += d->buildTermList(d->escapeString(term)); + queryList.append(QHelpSearchQuery(QHelpSearchQuery::ATLEAST, atLeast)); + } + } + return queryList; +#endif +} + +/*! \reimp +*/ +void QHelpSearchQueryWidget::focusInEvent(QFocusEvent *focusEvent) +{ + if (focusEvent->reason() != Qt::MouseFocusReason) { + d->defaultQuery->selectAll(); + d->defaultQuery->setFocus(); + } +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpsearchquerywidget.h b/tools/assistant/lib/qhelpsearchquerywidget.h new file mode 100644 index 0000000..f4bcf3e --- /dev/null +++ b/tools/assistant/lib/qhelpsearchquerywidget.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHQUERYWIDGET_H +#define QHELPSEARCHQUERYWIDGET_H + +#include <QtHelp/qhelp_global.h> +#include <QtHelp/qhelpsearchengine.h> + +#include <QtCore/QMap> +#include <QtCore/QString> +#include <QtCore/QStringList> + +#include <QtGui/QWidget> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Help) + +class QFocusEvent; +class QHelpSearchQueryWidgetPrivate; + +class QHELP_EXPORT QHelpSearchQueryWidget : public QWidget +{ + Q_OBJECT + +public: + QHelpSearchQueryWidget(QWidget *parent = 0); + ~QHelpSearchQueryWidget(); + + QList<QHelpSearchQuery> query() const; + +Q_SIGNALS: + void search(); + +private: + void focusInEvent(QFocusEvent *focusEvent); + +private: + QHelpSearchQueryWidgetPrivate *d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QHELPSEARCHQUERYWIDGET_H diff --git a/tools/assistant/lib/qhelpsearchresultwidget.cpp b/tools/assistant/lib/qhelpsearchresultwidget.cpp new file mode 100644 index 0000000..e72cf97 --- /dev/null +++ b/tools/assistant/lib/qhelpsearchresultwidget.cpp @@ -0,0 +1,439 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpsearchresultwidget.h" + +#include <QtCore/QList> +#include <QtCore/QString> +#include <QtCore/QPointer> +#include <QtCore/QStringList> + +#include <QtGui/QLabel> +#include <QtGui/QLayout> +#include <QtGui/QMouseEvent> +#include <QtGui/QHeaderView> +#include <QtGui/QSpacerItem> +#include <QtGui/QToolButton> +#include <QtGui/QTreeWidget> +#include <QtGui/QTextBrowser> +#include <QtGui/QTreeWidgetItem> + +QT_BEGIN_NAMESPACE + +class QDefaultResultWidget : public QTreeWidget +{ + Q_OBJECT + +public: + QDefaultResultWidget(QWidget *parent = 0) + : QTreeWidget(parent) + { + header()->hide(); + connect(this, SIGNAL(itemActivated(QTreeWidgetItem*, int)), + this, SLOT(itemActivated(QTreeWidgetItem*, int))); + } + + void showResultPage(const QList<QHelpSearchEngine::SearchHit> hits) + { + foreach (const QHelpSearchEngine::SearchHit hit, hits) + new QTreeWidgetItem(this, QStringList(hit.first) << hit.second); + } + +signals: + void requestShowLink(const QUrl &url); + +private slots: + void itemActivated(QTreeWidgetItem *item, int /* column */) + { + if (item) { + QString data = item->data(1, Qt::DisplayRole).toString(); + emit requestShowLink(data); + } + } +}; + + +class QCLuceneResultWidget : public QTextBrowser +{ + Q_OBJECT + +public: + QCLuceneResultWidget(QWidget *parent = 0) + : QTextBrowser(parent) + { + connect(this, SIGNAL(anchorClicked(const QUrl&)), + this, SIGNAL(requestShowLink(const QUrl&))); + setContextMenuPolicy(Qt::NoContextMenu); + } + + void showResultPage(const QList<QHelpSearchEngine::SearchHit> hits, bool isIndexing) + { + QString htmlFile = QString(QLatin1String("<html><head><title>%1</title></head><body>")) + .arg(tr("Search Results")); + + int count = hits.count(); + if (count != 0) { + if (isIndexing) + htmlFile += QString(QLatin1String("<div style=\"text-align:left; font-weight:bold; color:red\">" + "%1 <span style=\"font-weight:normal; color:black\">" + "%2</span></div></div><br>")).arg(tr("Note:")) + .arg(tr("The search results may not be complete since the " + "documentation is still being indexed!")); + + foreach (const QHelpSearchEngine::SearchHit hit, hits) { + htmlFile += QString(QLatin1String("<div style=\"text-align:left; font-weight:bold\"" + "><a href=\"%1\">%2</a><div style=\"color:green; font-weight:normal;" + " margin:5px\">%1</div></div><p></p>")) + .arg(hit.first).arg(hit.second); + } + } else { + htmlFile += QLatin1String("<div align=\"center\"><br><br><h2>") + + tr("Your search did not match any documents.") + + QLatin1String("</h2><div>"); + if (isIndexing) + htmlFile += QLatin1String("<div align=\"center\"><h3>") + + tr("(The reason for this might be that the documentation " + "is still being indexed.)") + + QLatin1String("</h3><div>"); + } + + htmlFile += QLatin1String("</body></html>"); + + setHtml(htmlFile); + } + +signals: + void requestShowLink(const QUrl &url); + +private slots: + void setSource(const QUrl & /* name */) {} +}; + + +class QHelpSearchResultWidgetPrivate : public QObject +{ + Q_OBJECT + +private slots: + void setResults(int hitsCount) + { + if (!searchEngine.isNull()) { +#if defined(QT_CLUCENE_SUPPORT) + showFirstResultPage(); + updateNextButtonState(((hitsCount > 20) ? true : false)); +#else + resultTreeWidget->clear(); + resultTreeWidget->showResultPage(searchEngine->hits(0, hitsCount)); +#endif + } + } + + void showNextResultPage() + { + if (!searchEngine.isNull() + && resultLastToShow < searchEngine->hitsCount()) { + resultLastToShow += 20; + resultFirstToShow += 20; + + resultTextBrowser->showResultPage(searchEngine->hits(resultFirstToShow, + resultLastToShow), isIndexing); + if (resultLastToShow >= searchEngine->hitsCount()) + updateNextButtonState(false); + } + updateHitRange(); + } + + void showLastResultPage() + { + if (!searchEngine.isNull()) { + resultLastToShow = searchEngine->hitsCount(); + resultFirstToShow = resultLastToShow - (resultLastToShow % 20); + + if (resultFirstToShow == resultLastToShow) + resultFirstToShow -= 20; + + resultTextBrowser->showResultPage(searchEngine->hits(resultFirstToShow, + resultLastToShow), isIndexing); + updateNextButtonState(false); + } + updateHitRange(); + } + + void showFirstResultPage() + { + if (!searchEngine.isNull()) { + resultLastToShow = 20; + resultFirstToShow = 0; + + resultTextBrowser->showResultPage(searchEngine->hits(resultFirstToShow, + resultLastToShow), isIndexing); + updatePrevButtonState(false); + } + updateHitRange(); + } + + void showPreviousResultPage() + { + if (!searchEngine.isNull()) { + int count = resultLastToShow % 20; + if (count == 0 || resultLastToShow != searchEngine->hitsCount()) + count = 20; + + resultLastToShow -= count; + resultFirstToShow = resultLastToShow -20; + + resultTextBrowser->showResultPage(searchEngine->hits(resultFirstToShow, + resultLastToShow), isIndexing); + if (resultFirstToShow == 0) + updatePrevButtonState(false); + } + updateHitRange(); + } + + void updatePrevButtonState(bool state = true) + { + firstResultPage->setEnabled(state); + previousResultPage->setEnabled(state); + } + + void updateNextButtonState(bool state = true) + { + nextResultPage->setEnabled(state); + lastResultPage->setEnabled(state); + } + + void indexingStarted() + { + isIndexing = true; + } + + void indexingFinished() + { + isIndexing = false; + } + +private: + QHelpSearchResultWidgetPrivate(QHelpSearchEngine *engine) + : QObject() + , searchEngine(engine) + , isIndexing(false) + { + resultTreeWidget = 0; + resultTextBrowser = 0; + + resultLastToShow = 20; + resultFirstToShow = 0; + + firstResultPage = 0; + previousResultPage = 0; + hitsLabel = 0; + nextResultPage = 0; + lastResultPage = 0; + + connect(searchEngine, SIGNAL(indexingStarted()), + this, SLOT(indexingStarted())); + connect(searchEngine, SIGNAL(indexingFinished()), + this, SLOT(indexingFinished())); + } + + ~QHelpSearchResultWidgetPrivate() + { + delete searchEngine; + } + + QToolButton* setupToolButton(const QString &iconPath) + { + QToolButton *button = new QToolButton(); + button->setEnabled(false); + button->setAutoRaise(true); + button->setIcon(QIcon(iconPath)); + button->setIconSize(QSize(12, 12)); + button->setMaximumSize(QSize(16, 16)); + + return button; + } + + void updateHitRange() + { + int last = 0; + int first = 0; + int count = 0; + + if (!searchEngine.isNull()) { + count = searchEngine->hitsCount(); + if (count > 0) { + first = resultFirstToShow +1; + last = resultLastToShow > count ? count : resultLastToShow; + } + } + hitsLabel->setText(tr("%1 - %2 of %3 Hits").arg(first).arg(last).arg(count)); + } + +private: + friend class QHelpSearchResultWidget; + + QPointer<QHelpSearchEngine> searchEngine; + + QDefaultResultWidget *resultTreeWidget; + QCLuceneResultWidget *resultTextBrowser; + + int resultLastToShow; + int resultFirstToShow; + bool isIndexing; + + QToolButton *firstResultPage; + QToolButton *previousResultPage; + QLabel *hitsLabel; + QToolButton *nextResultPage; + QToolButton *lastResultPage; +}; + +#include "qhelpsearchresultwidget.moc" + + +/*! + \class QHelpSearchResultWidget + \since 4.4 + \inmodule QtHelp + \brief The QHelpSearchResultWidget class provides either a tree + widget or a text browser depending on the used search engine to display + the hits found by the search. +*/ + +/*! + \fn void QHelpSearchResultWidget::requestShowLink(const QUrl &link) + + This signal is emitted when a item is activated and its associated + \a link should be shown. +*/ + +QHelpSearchResultWidget::QHelpSearchResultWidget(QHelpSearchEngine *engine) + : QWidget(0) + , d(new QHelpSearchResultWidgetPrivate(engine)) +{ + QVBoxLayout *vLayout = new QVBoxLayout(this); + vLayout->setMargin(0); + vLayout->setSpacing(0); + +#if defined(QT_CLUCENE_SUPPORT) + QHBoxLayout *hBoxLayout = new QHBoxLayout(); +#ifndef Q_OS_MAC + hBoxLayout->setMargin(0); + hBoxLayout->setSpacing(0); +#endif + hBoxLayout->addWidget(d->firstResultPage = d->setupToolButton( + QString::fromUtf8(":/trolltech/assistant/images/3leftarrow.png"))); + + hBoxLayout->addWidget(d->previousResultPage = d->setupToolButton( + QString::fromUtf8(":/trolltech/assistant/images/1leftarrow.png"))); + + d->hitsLabel = new QLabel(tr("0 - 0 of 0 Hits"), this); + d->hitsLabel->setEnabled(false); + hBoxLayout->addWidget(d->hitsLabel); + d->hitsLabel->setAlignment(Qt::AlignCenter); + d->hitsLabel->setMinimumSize(QSize(150, d->hitsLabel->height())); + + hBoxLayout->addWidget(d->nextResultPage = d->setupToolButton( + QString::fromUtf8(":/trolltech/assistant/images/1rightarrow.png"))); + + hBoxLayout->addWidget(d->lastResultPage = d->setupToolButton( + QString::fromUtf8(":/trolltech/assistant/images/3rightarrow.png"))); + + QSpacerItem *spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + hBoxLayout->addItem(spacer); + + vLayout->addLayout(hBoxLayout); + + d->resultTextBrowser = new QCLuceneResultWidget(this); + vLayout->addWidget(d->resultTextBrowser); + + connect(d->resultTextBrowser, SIGNAL(requestShowLink(const QUrl&)), this, + SIGNAL(requestShowLink(const QUrl&))); + + connect(d->nextResultPage, SIGNAL(clicked()), d, SLOT(showNextResultPage())); + connect(d->lastResultPage, SIGNAL(clicked()), d, SLOT(showLastResultPage())); + connect(d->firstResultPage, SIGNAL(clicked()), d, SLOT(showFirstResultPage())); + connect(d->previousResultPage, SIGNAL(clicked()), d, SLOT(showPreviousResultPage())); + + connect(d->firstResultPage, SIGNAL(clicked()), d, SLOT(updateNextButtonState())); + connect(d->previousResultPage, SIGNAL(clicked()), d, SLOT(updateNextButtonState())); + connect(d->nextResultPage, SIGNAL(clicked()), d, SLOT(updatePrevButtonState())); + connect(d->lastResultPage, SIGNAL(clicked()), d, SLOT(updatePrevButtonState())); + +#else + d->resultTreeWidget = new QDefaultResultWidget(this); + vLayout->addWidget(d->resultTreeWidget); + connect(d->resultTreeWidget, SIGNAL(requestShowLink(const QUrl&)), this, + SIGNAL(requestShowLink(const QUrl&))); +#endif + + connect(engine, SIGNAL(searchingFinished(int)), d, SLOT(setResults(int))); +} + +/*! + Destroys the search result widget. +*/ +QHelpSearchResultWidget::~QHelpSearchResultWidget() +{ + delete d; +} + +/*! + Returns a reference of the URL that the item at \a point owns, or an + empty URL if no item exists at that point. +*/ +QUrl QHelpSearchResultWidget::linkAt(const QPoint &point) +{ + QUrl url; +#if defined(QT_CLUCENE_SUPPORT) + if (d->resultTextBrowser) + url = d->resultTextBrowser->anchorAt(point); +#else + if (d->resultTreeWidget) { + QTreeWidgetItem *item = d->resultTreeWidget->itemAt(point); + if (item) + url = item->data(1, Qt::DisplayRole).toString(); + } +#endif + return url; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpsearchresultwidget.h b/tools/assistant/lib/qhelpsearchresultwidget.h new file mode 100644 index 0000000..26bc1d97 --- /dev/null +++ b/tools/assistant/lib/qhelpsearchresultwidget.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHRESULTWIDGET_H +#define QHELPSEARCHRESULTWIDGET_H + +#include <QtHelp/qhelpsearchengine.h> +#include <QtHelp/qhelp_global.h> + +#include <QtCore/QUrl> +#include <QtCore/QPoint> +#include <QtCore/QObject> + +#include <QtGui/QWidget> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Help) + +class QHelpSearchResultWidgetPrivate; + +class QHELP_EXPORT QHelpSearchResultWidget : public QWidget +{ + Q_OBJECT + +public: + ~QHelpSearchResultWidget(); + QUrl linkAt(const QPoint &point); + +Q_SIGNALS: + void requestShowLink(const QUrl &url); + +private: + friend class QHelpSearchEngine; + + QHelpSearchResultWidgetPrivate *d; + QHelpSearchResultWidget(QHelpSearchEngine *engine); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QHELPSEARCHRESULTWIDGET_H diff --git a/tools/assistant/tools/assistant/Info_mac.plist b/tools/assistant/tools/assistant/Info_mac.plist new file mode 100644 index 0000000..76369a1 --- /dev/null +++ b/tools/assistant/tools/assistant/Info_mac.plist @@ -0,0 +1,18 @@ +<?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</string> + <key>CFBundleExecutable</key> + <string>@EXECUTABLE@</string> +</dict> +</plist> diff --git a/tools/assistant/tools/assistant/aboutdialog.cpp b/tools/assistant/tools/assistant/aboutdialog.cpp new file mode 100644 index 0000000..629f249 --- /dev/null +++ b/tools/assistant/tools/assistant/aboutdialog.cpp @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QBuffer> + +#include <QtGui/QLabel> +#include <QtGui/QPushButton> +#include <QtGui/QLayout> +#include <QtGui/QApplication> +#include <QtGui/QDesktopWidget> +#include <QtGui/QMessageBox> +#include <QtGui/QDesktopServices> + +#include "aboutdialog.h" + +QT_BEGIN_NAMESPACE + +AboutLabel::AboutLabel(QWidget *parent) + : QTextBrowser(parent) +{ + setFrameStyle(QFrame::NoFrame); + QPalette p; + p.setColor(QPalette::Base, p.color(QPalette::Background)); + setPalette(p); +} + +void AboutLabel::setText(const QString &text, const QByteArray &resources) +{ + QDataStream in(resources); + in >> m_resourceMap; + + QTextBrowser::setText(text); +} + +QSize AboutLabel::minimumSizeHint() const +{ + QTextDocument *doc = document(); + doc->adjustSize(); + return QSize(int(doc->size().width()), int(doc->size().height())); +} + +QVariant AboutLabel::loadResource(int type, const QUrl &name) +{ + if (type == 2 || type == 3) { + if (m_resourceMap.contains(name.toString())) { + return m_resourceMap.value(name.toString()); + } + } + return QVariant(); +} + +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")))) { + if (!QDesktopServices::openUrl(url)) { + QMessageBox::warning(this, tr("Warning"), + tr("Unable to launch external application.\n"), + tr("OK")); + } + } +} + +AboutDialog::AboutDialog(QWidget *parent) + : QDialog(parent, Qt::MSWindowsFixedSizeDialogHint|Qt::WindowTitleHint|Qt::WindowSystemMenuHint) +{ + m_pixmapLabel = 0; + m_aboutLabel = new AboutLabel(); + + m_closeButton = new QPushButton(); + m_closeButton->setText(tr("&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, 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); +} + +void AboutDialog::setText(const QString &text, const QByteArray &resources) +{ + m_aboutLabel->setText(text, resources); + updateSize(); +} + +void AboutDialog::setPixmap(const QPixmap &pixmap) +{ + if (!m_pixmapLabel) { + m_pixmapLabel = new QLabel(); + m_layout->addWidget(m_pixmapLabel, 0, 0, 1, -1, Qt::AlignCenter); + } + m_pixmapLabel->setPixmap(pixmap); + updateSize(); +} + +QString AboutDialog::documentTitle() const +{ + return m_aboutLabel->documentTitle(); +} + +void AboutDialog::updateSize() +{ + QSize screenSize = QApplication::desktop()->availableGeometry(QCursor::pos()).size(); + int limit = qMin(screenSize.width()/2, 500); + +#ifdef Q_WS_MAC + limit = qMin(screenSize.width()/2, 420); +#endif + + layout()->activate(); + int width = layout()->totalMinimumSize().width(); + + if (width > limit) + width = limit; + + QFontMetrics fm(qApp->font("QWorkspaceTitleBar")); + int windowTitleWidth = qMin(fm.width(windowTitle()) + 50, limit); + if (windowTitleWidth > width) + width = windowTitleWidth; + + layout()->activate(); + int height = (layout()->hasHeightForWidth()) + ? layout()->totalHeightForWidth(width) + : layout()->totalMinimumSize().height(); + setFixedSize(width, height); + QCoreApplication::removePostedEvents(this, QEvent::LayoutRequest); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/aboutdialog.h b/tools/assistant/tools/assistant/aboutdialog.h new file mode 100644 index 0000000..d62a220 --- /dev/null +++ b/tools/assistant/tools/assistant/aboutdialog.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ABOUTDIALOG_H +#define ABOUTDIALOG_H + +#include <QtGui/QTextBrowser> +#include <QtGui/QDialog> + +QT_BEGIN_NAMESPACE + +class QLabel; +class QPushButton; +class QGridLayout; + +class AboutLabel : public QTextBrowser +{ + Q_OBJECT + +public: + AboutLabel(QWidget *parent = 0); + void setText(const QString &text, const QByteArray &resources); + QSize minimumSizeHint() const; + +private: + QVariant loadResource(int type, const QUrl &name); + void setSource(const QUrl &url); + + QMap<QString, QByteArray> m_resourceMap; +}; + +class AboutDialog : public QDialog +{ + Q_OBJECT + +public: + AboutDialog(QWidget *parent = 0); + void setText(const QString &text, const QByteArray &resources); + void setPixmap(const QPixmap &pixmap); + QString documentTitle() const; + +private: + void updateSize(); + + QLabel *m_pixmapLabel; + AboutLabel *m_aboutLabel; + QPushButton *m_closeButton; + QGridLayout *m_layout; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/tools/assistant/assistant.icns b/tools/assistant/tools/assistant/assistant.icns Binary files differnew file mode 100644 index 0000000..6291dd3 --- /dev/null +++ b/tools/assistant/tools/assistant/assistant.icns diff --git a/tools/assistant/tools/assistant/assistant.ico b/tools/assistant/tools/assistant/assistant.ico Binary files differnew file mode 100644 index 0000000..9e1b83f --- /dev/null +++ b/tools/assistant/tools/assistant/assistant.ico diff --git a/tools/assistant/tools/assistant/assistant.pro b/tools/assistant/tools/assistant/assistant.pro new file mode 100644 index 0000000..1cbd1d3 --- /dev/null +++ b/tools/assistant/tools/assistant/assistant.pro @@ -0,0 +1,89 @@ +include($$QT_SOURCE_TREE/tools/shared/fontpanel/fontpanel.pri) + +TEMPLATE = app +LANGUAGE = C++ +TARGET = assistant + +DEFINES += QT_CLUCENE_SUPPORT + +contains(QT_CONFIG, webkit) { + QT += webkit +} + +CONFIG += qt warn_on help + +QT += network + +PROJECTNAME = Assistant +DESTDIR = ../../../../bin + +target.path=$$[QT_INSTALL_BINS] +INSTALLS += target + +### 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 + +win32 { + HEADERS += remotecontrol_win.h +} + +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 + +RESOURCES += assistant.qrc assistant_images.qrc + +win32 { + !wince*:LIBS += -lshell32 + RC_FILE = assistant.rc +} + +mac { + ICON = assistant.icns + TARGET = Assistant + QMAKE_INFO_PLIST = Info_mac.plist +} + +contains(CONFIG, static): { + SQLPLUGINS = $$unique(sql-plugins) + contains(SQLPLUGINS, sqlite): { + QTPLUGIN += qsqlite + DEFINES += USE_STATIC_SQLITE_PLUGIN + } +} diff --git a/tools/assistant/tools/assistant/assistant.qch b/tools/assistant/tools/assistant/assistant.qch Binary files differnew file mode 100644 index 0000000..550cd89 --- /dev/null +++ b/tools/assistant/tools/assistant/assistant.qch diff --git a/tools/assistant/tools/assistant/assistant.qrc b/tools/assistant/tools/assistant/assistant.qrc new file mode 100644 index 0000000..dddf1be --- /dev/null +++ b/tools/assistant/tools/assistant/assistant.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/trolltech/assistant" > + <file>assistant.qch</file> + </qresource> +</RCC> diff --git a/tools/assistant/tools/assistant/assistant.rc b/tools/assistant/tools/assistant/assistant.rc new file mode 100644 index 0000000..b4786ce --- /dev/null +++ b/tools/assistant/tools/assistant/assistant.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "assistant.ico" diff --git a/tools/assistant/tools/assistant/assistant_images.qrc b/tools/assistant/tools/assistant/assistant_images.qrc new file mode 100644 index 0000000..58e03b5 --- /dev/null +++ b/tools/assistant/tools/assistant/assistant_images.qrc @@ -0,0 +1,36 @@ +<RCC> + <qresource prefix="/trolltech/assistant" > + <file>images/trolltech-logo.png</file> + <file>images/assistant-128.png</file> + <file>images/assistant.png</file> + <file>images/wrap.png</file> +#mac + <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/previous.png</file> + <file>images/mac/print.png</file> + <file>images/mac/synctoc.png</file> + <file>images/mac/zoomin.png</file> + <file>images/mac/zoomout.png</file> + <file>images/mac/resetzoom.png</file> +#win + <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/zoomin.png</file> + <file>images/win/zoomout.png</file> + <file>images/win/resetzoom.png</file> + </qresource> +</RCC> diff --git a/tools/assistant/tools/assistant/bookmarkdialog.ui b/tools/assistant/tools/assistant/bookmarkdialog.ui new file mode 100644 index 0000000..7a878f9 --- /dev/null +++ b/tools/assistant/tools/assistant/bookmarkdialog.ui @@ -0,0 +1,146 @@ +<ui version="4.0" > + <class>BookmarkDialog</class> + <widget class="QDialog" name="BookmarkDialog" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>450</width> + <height>135</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="Preferred" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="windowTitle" > + <string>Add Bookmark</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3" > + <item> + <layout class="QHBoxLayout" name="horizontalLayout" > + <item> + <layout class="QVBoxLayout" name="verticalLayout_2" > + <item> + <widget class="QLabel" name="label" > + <property name="text" > + <string>Bookmark:</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_2" > + <property name="text" > + <string>Add in Folder:</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout" > + <item> + <widget class="QLineEdit" name="bookmarkEdit" /> + </item> + <item> + <widget class="QComboBox" name="bookmarkFolders" /> + </item> + </layout> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_3" > + <item> + <widget class="QToolButton" name="toolButton" > + <property name="minimumSize" > + <size> + <width>25</width> + <height>20</height> + </size> + </property> + <property name="text" > + <string>+</string> + </property> + </widget> + </item> + <item> + <widget class="Line" name="line" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QTreeView" name="treeView" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Ignored" hsizetype="Expanding" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_4" > + <item> + <widget class="QPushButton" name="newFolderButton" > + <property name="text" > + <string>New Folder</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> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>BookmarkDialog</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>BookmarkDialog</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/assistant/tools/assistant/bookmarkmanager.cpp b/tools/assistant/tools/assistant/bookmarkmanager.cpp new file mode 100644 index 0000000..6f5732f --- /dev/null +++ b/tools/assistant/tools/assistant/bookmarkmanager.cpp @@ -0,0 +1,874 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "bookmarkmanager.h" +#include "centralwidget.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) +{ + installEventFilter(this); + + ui.setupUi(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(const QString&)), this, + SLOT(textChanged(const QString&))); + + connect(bookmarkManager->treeBookmarkModel(), SIGNAL(itemChanged(QStandardItem*)), + this, SLOT(itemChanged(QStandardItem*))); + + connect(ui.bookmarkFolders, SIGNAL(currentIndexChanged(const QString&)), this, + SLOT(selectBookmarkFolder(const QString&))); + + connect(ui.treeView, SIGNAL(customContextMenuRequested(const QPoint&)), this, + SLOT(customContextMenuRequested(const QPoint&))); + + connect(ui.treeView->selectionModel(), + SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), + this, SLOT(currentChanged(const QModelIndex&, const QModelIndex&))); +} + +BookmarkDialog::~BookmarkDialog() +{ +} + +void BookmarkDialog::addAccepted() +{ + const QItemSelection selection = ui.treeView->selectionModel()->selection(); + const QModelIndexList list = selection.indexes(); + + QModelIndex index; + if (!list.isEmpty()) + index = proxyModel->mapToSource(list.at(0)); + + bookmarkManager->addNewBookmark(index, ui.bookmarkEdit->text(), m_url); + accept(); +} + +void BookmarkDialog::addNewFolder() +{ + const QItemSelection selection = ui.treeView->selectionModel()->selection(); + const QModelIndexList list = 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); + ui.treeView->selectionModel()->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)); + } + ui.treeView->setFocus(); +} + +void BookmarkDialog::toolButtonClicked() +{ + 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::itemChanged(QStandardItem *item) +{ + if (renameItem != item) { + renameItem = item; + oldText = item->text(); + return; + } + + if (item->text() != oldText) { + ui.bookmarkFolders->clear(); + ui.bookmarkFolders->addItems(bookmarkManager->bookmarkFolders()); + + 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) +{ + ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!string.isEmpty()); +} + +void BookmarkDialog::selectBookmarkFolder(const QString &folderName) +{ + 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()) { + QModelIndex index = model->indexFromItem(list.at(0)); + ui.treeView->selectionModel()->setCurrentIndex( + proxyModel->mapFromSource(index), QItemSelectionModel::ClearAndSelect); + } +} + +void BookmarkDialog::customContextMenuRequested(const QPoint &point) +{ + QModelIndex index = ui.treeView->indexAt(point); + if (!index.isValid()) + return; + + QMenu menu(QLatin1String(""), this); + + QAction *removeItem = menu.addAction(tr("Delete Folder")); + QAction *renameItem = menu.addAction(tr("Rename Folder")); + + QAction *picked_action = menu.exec(ui.treeView->mapToGlobal(point)); + if (!picked_action) + return; + + if (picked_action == removeItem) { + bookmarkManager->removeBookmarkItem(ui.treeView, + proxyModel->mapToSource(index)); + 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_action == renameItem) { + QStandardItem *item = bookmarkManager->treeBookmarkModel()-> + itemFromIndex(proxyModel->mapToSource(index)); + if (item) { + item->setEditable(true); + ui.treeView->edit(index); + item->setEditable(false); + } + } +} + +void BookmarkDialog::currentChanged(const QModelIndex& current, + const QModelIndex& previous) +{ + Q_UNUSED(previous) + + if (!current.isValid()) { + ui.bookmarkFolders->setCurrentIndex( + ui.bookmarkFolders->findText(tr("Bookmarks"))); + return; + } + + ui.bookmarkFolders->setCurrentIndex( + ui.bookmarkFolders->findText(current.data().toString())); +} + +bool BookmarkDialog::eventFilter(QObject *object, QEvent *e) +{ + if (object == this && e->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast<QKeyEvent*>(e); + + QModelIndex index = ui.treeView->currentIndex(); + switch (ke->key()) { + case Qt::Key_F2: { + 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: { + bookmarkManager->removeBookmarkItem(ui.treeView, + proxyModel->mapToSource(index)); + 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)); + } break; + + default: + break; + } + } + return QObject::eventFilter(object, e); +} + + + + +BookmarkWidget::BookmarkWidget(BookmarkManager *manager, QWidget *parent, + bool showButtons) + : QWidget(parent) + , addButton(0) + , removeButton(0) + , bookmarkManager(manager) +{ + setup(showButtons); + installEventFilter(this); +} + +BookmarkWidget::~BookmarkWidget() +{ +} + +void BookmarkWidget::removeClicked() +{ + const QModelIndex& index = treeView->currentIndex(); + if (searchField->text().isEmpty()) { + bookmarkManager->removeBookmarkItem(treeView, + filterBookmarkModel->mapToSource(index)); + } +} + +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()); + } + + if (addButton) + addButton->setEnabled(searchBookmarks); + + if (removeButton) + removeButton->setEnabled(searchBookmarks); + + filterBookmarkModel->setFilterRegExp(regExp); + + QModelIndex index = treeView->indexAt(QPoint(1, 1)); + if (index.isValid()) + treeView->setCurrentIndex(index); + + if (searchBookmarks) + expandItems(); +} + +void BookmarkWidget::expand(const QModelIndex& index) +{ + const QModelIndex& source = filterBookmarkModel->mapToSource(index); + QStandardItem *item = bookmarkManager->treeBookmarkModel()->itemFromIndex(source); + if (item) + item->setData(treeView->isExpanded(index), Qt::UserRole + 11); +} + +void BookmarkWidget::activated(const QModelIndex &index) +{ + if (!index.isValid()) + return; + + QString data = index.data(Qt::UserRole + 10).toString(); + if (data != QLatin1String("Folder")) + emit requestShowLink(data); +} + +void BookmarkWidget::customContextMenuRequested(const QPoint &point) +{ + QModelIndex index = treeView->indexAt(point); + if (!index.isValid()) + return; + + 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")); + } + } + + QAction *picked_action = menu.exec(treeView->mapToGlobal(point)); + if (!picked_action) + return; + + if (picked_action == showItem) { + emit requestShowLink(data); + } + else if (picked_action == showItemNewTab) { + CentralWidget::instance()->setSourceInNewTab(data); + } + else if (picked_action == removeItem) { + bookmarkManager->removeBookmarkItem(treeView, + filterBookmarkModel->mapToSource(index)); + } + else if (picked_action == renameItem) { + const QModelIndex& source = filterBookmarkModel->mapToSource(index); + QStandardItem *item = + bookmarkManager->treeBookmarkModel()->itemFromIndex(source); + if (item) { + item->setEditable(true); + treeView->edit(index); + item->setEditable(false); + } + } +} + +void BookmarkWidget::setup(bool showButtons) +{ + 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(const QString &)), this, + SLOT(filterChanged())); + + treeView = new TreeView(this); + vlayout->addWidget(treeView); + + QString system = QLatin1String("win"); +#ifdef Q_OS_MAC + system = QLatin1String("mac"); +#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(QString::fromUtf8( + ":/trolltech/assistant/images/%1/addtab.png").arg(system))); + 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(QString::fromUtf8( + ":/trolltech/assistant/images/%1/closetab.png").arg(system))); + 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->viewport()->installEventFilter(this); + treeView->setContextMenuPolicy(Qt::CustomContextMenu); + + connect(treeView, SIGNAL(expanded(const QModelIndex&)), this, + SLOT(expand(const QModelIndex&))); + + connect(treeView, SIGNAL(collapsed(const QModelIndex&)), this, + SLOT(expand(const QModelIndex&))); + + connect(treeView, SIGNAL(activated(const QModelIndex&)), this, + SLOT(activated(const QModelIndex&))); + + connect(treeView, SIGNAL(customContextMenuRequested(const QPoint&)), + this, SLOT(customContextMenuRequested(const QPoint&))); + + filterBookmarkModel->setFilterKeyColumn(0); + filterBookmarkModel->setDynamicSortFilter(true); + filterBookmarkModel->setSourceModel(bookmarkManager->treeBookmarkModel()); + + expandItems(); +} + +void BookmarkWidget::expandItems() +{ + 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()); + } +} + +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); + + } +} + +bool BookmarkWidget::eventFilter(QObject *object, QEvent *e) +{ + if (object == this && e->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast<QKeyEvent*>(e); + QModelIndex index = treeView->currentIndex(); + switch (ke->key()) { + if (index.isValid() && searchField->text().isEmpty()) { + case Qt::Key_F2: { + const QModelIndex& source = filterBookmarkModel->mapToSource(index); + QStandardItem *item = + bookmarkManager->treeBookmarkModel()->itemFromIndex(source); + if (item) { + item->setEditable(true); + treeView->edit(index); + item->setEditable(false); + } + } break; + + case Qt::Key_Delete: { + bookmarkManager->removeBookmarkItem(treeView, + filterBookmarkModel->mapToSource(index)); + } break; + } + + case Qt::Key_Up: + case Qt::Key_Down: + treeView->subclassKeyPressEvent(ke); + break; + + case Qt::Key_Enter: { + case Qt::Key_Return: + index = treeView->selectionModel()->currentIndex(); + if (index.isValid()) { + QString data = index.data(Qt::UserRole + 10).toString(); + if (!data.isEmpty() && data != QLatin1String("Folder")) + emit requestShowLink(data); + } + } break; + + case Qt::Key_Escape: + emit escapePressed(); + break; + + default: + break; + } + } + else if (object == treeView->viewport() && e->type() == QEvent::MouseButtonRelease) { + const QModelIndex& index = treeView->currentIndex(); + QMouseEvent *me = static_cast<QMouseEvent*>(e); + if (index.isValid() && (me->button() == Qt::MidButton)) { + QString data = index.data(Qt::UserRole + 10).toString(); + if (!data.isEmpty() && data != QLatin1String("Folder")) + CentralWidget::instance()->setSourceInNewTab(data); + } + } + return QWidget::eventFilter(object, e); +} + + + + +BookmarkModel::BookmarkModel(int rows, int columns, QObject * parent) + : QStandardItemModel(rows, columns, parent) +{ +} + +BookmarkModel::~BookmarkModel() +{ +} + +Qt::DropActions BookmarkModel::supportedDropActions() const +{ + return Qt::MoveAction; +} + +Qt::ItemFlags BookmarkModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags defaultFlags = QStandardItemModel::flags(index); + if (index.data(Qt::UserRole + 10).toString() == QLatin1String("Folder")) + return (Qt::ItemIsDropEnabled | defaultFlags) &~ Qt::ItemIsDragEnabled; + + return (Qt::ItemIsDragEnabled | defaultFlags) &~ Qt::ItemIsDropEnabled; +} + + + + +BookmarkManager::BookmarkManager(QHelpEngineCore* _helpEngine) + : treeModel(new BookmarkModel(0, 1, this)) + , listModel(new BookmarkModel(0, 1, this)) + , helpEngine(_helpEngine) +{ + folderIcon = QApplication::style()->standardIcon(QStyle::SP_DirClosedIcon); + treeModel->setHeaderData(0, Qt::Horizontal, QObject::tr("Bookmark")); + listModel->setHeaderData(0, Qt::Horizontal, QObject::tr("Bookmark")); + + connect(treeModel, SIGNAL(itemChanged(QStandardItem*)), this, + SLOT(itemChanged(QStandardItem*))); +} + +BookmarkManager::~BookmarkManager() +{ + treeModel->clear(); + listModel->clear(); +} + +BookmarkModel* BookmarkManager::treeBookmarkModel() +{ + return treeModel; +} + +BookmarkModel* BookmarkManager::listBookmarkModel() +{ + return listModel; +} + +void BookmarkManager::saveBookmarks() +{ + qint32 depth = 0; + QByteArray bookmarks; + QDataStream stream(&bookmarks, QIODevice::WriteOnly); + QStandardItem *root = treeModel->invisibleRootItem(); + + for (int i = 0; i < root->rowCount(); ++i) { + const QStandardItem *item = root->child(i); + stream << depth; // root + stream << item->data(Qt::DisplayRole).toString(); + stream << item->data(Qt::UserRole + 10).toString(); + stream << item->data(Qt::UserRole + 11).toBool(); + + if (item->rowCount() > 0) { + readBookmarksRecursive(item, stream, (depth +1)); + } + } + helpEngine->setCustomValue(QLatin1String("Bookmarks"), bookmarks); +} + +QStringList BookmarkManager::bookmarkFolders() const +{ + QStringList folders(tr("Bookmarks")); + + 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; +} + +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); +} + +void BookmarkManager::removeBookmarkItem(QTreeView *treeView, 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()); + } +} + +void BookmarkManager::showBookmarkDialog(QWidget* parent, const QString &name, + const QString &url) +{ + BookmarkDialog dialog(this, name, url, parent); + dialog.exec(); +} + +void BookmarkManager::addNewBookmark(const QModelIndex& index, + const QString &name, const QString &url) +{ + QStandardItem *item = new QStandardItem(name); + item->setEditable(false); + item->setData(false, Qt::UserRole + 11); + item->setData(url, Qt::UserRole + 10); + + if (index.isValid()) { + treeModel->itemFromIndex(index)->appendRow(item); + listModel->appendRow(item->clone()); + } else { + treeModel->appendRow(item); + listModel->appendRow(item->clone()); + } +} + +void BookmarkManager::itemChanged(QStandardItem *item) +{ + if (renameItem != item) { + renameItem = item; + oldText = item->text(); + 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()); + } + } +} + +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; + } + } + + if (type == QLatin1String("Folder")) + item->setIcon(folderIcon); + else + listModel->appendRow(item->clone()); + } +} + +QString BookmarkManager::uniqueFolderName() const +{ + 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; +} + +void BookmarkManager::removeBookmarkFolderItems(QStandardItem *item) +{ + 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; + } + } + } +} + +void BookmarkManager::readBookmarksRecursive(const QStandardItem *item, + QDataStream &stream, + const qint32 depth) const +{ + 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)); + } +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/bookmarkmanager.h b/tools/assistant/tools/assistant/bookmarkmanager.h new file mode 100644 index 0000000..ab905d1 --- /dev/null +++ b/tools/assistant/tools/assistant/bookmarkmanager.h @@ -0,0 +1,205 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $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 <QtGui/QTreeView> +#include <QtGui/QStandardItemModel> + +QT_BEGIN_NAMESPACE + +class QEvent; +class QLineEdit; +class QTreeView; +class QToolButton; +class QStandardItem; +class QHelpEngineCore; +class QAbstractItemModel; +class QSortFilterProxyModel; + +class BookmarkManager; + +class BookmarkDialog : public QDialog +{ + Q_OBJECT + +public: + BookmarkDialog(BookmarkManager *manager, const QString &title, + const QString &url, QWidget *parent = 0); + ~BookmarkDialog(); + +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, const QModelIndex& previous); + +private: + bool eventFilter(QObject *object, QEvent *e); + +private: + QString m_url; + QString m_title; + + QString oldText; + QStandardItem *renameItem; + + Ui::BookmarkDialog ui; + BookmarkManager *bookmarkManager; + QSortFilterProxyModel *proxyModel; +}; + +class TreeView : public QTreeView { + Q_OBJECT +public: + TreeView(QWidget* parent = 0) : QTreeView(parent) {} + void subclassKeyPressEvent(QKeyEvent* event) + { + QTreeView::keyPressEvent(event); + } +}; + +class BookmarkWidget : public QWidget +{ + Q_OBJECT + +public: + BookmarkWidget(BookmarkManager *manager, QWidget *parent = 0, + bool showButtons = true); + ~BookmarkWidget(); + +signals: + void addBookmark(); + void requestShowLink(const QUrl &url); + void escapePressed(); + +private slots: + void removeClicked(); + void filterChanged(); + void expand(const QModelIndex& index); + void activated(const QModelIndex &index); + void customContextMenuRequested(const QPoint &point); + +private: + void setup(bool showButtons); + void expandItems(); + void focusInEvent(QFocusEvent *e); + bool eventFilter(QObject *object, QEvent *event); + +private: + QRegExp regExp; + TreeView *treeView; + QLineEdit *searchField; + QToolButton *addButton; + QToolButton *removeButton; + BookmarkManager *bookmarkManager; + QSortFilterProxyModel* filterBookmarkModel; +}; + +class BookmarkModel : public QStandardItemModel +{ + Q_OBJECT + +public: + BookmarkModel(int rows, int columns, QObject *parent = 0); + ~BookmarkModel(); + + Qt::DropActions supportedDropActions() const; + Qt::ItemFlags flags(const QModelIndex &index) const; +}; + +class BookmarkManager : public QObject +{ + Q_OBJECT + +public: + BookmarkManager(QHelpEngineCore* helpEngine); + ~BookmarkManager(); + + 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(); + +private slots: + void itemChanged(QStandardItem *item); + +private: + QString uniqueFolderName() const; + void removeBookmarkFolderItems(QStandardItem *item); + void readBookmarksRecursive(const QStandardItem *item, QDataStream &stream, + const qint32 depth) const; + +private: + QString oldText; + QIcon folderIcon; + + BookmarkModel *treeModel; + BookmarkModel *listModel; + QStandardItem *renameItem; + QHelpEngineCore *helpEngine; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/tools/assistant/centralwidget.cpp b/tools/assistant/tools/assistant/centralwidget.cpp new file mode 100644 index 0000000..1b0e671 --- /dev/null +++ b/tools/assistant/tools/assistant/centralwidget.cpp @@ -0,0 +1,1080 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "centralwidget.h" +#include "helpviewer.h" +#include "searchwidget.h" +#include "mainwindow.h" + +#include <QtCore/QDir> +#include <QtCore/QEvent> +#include <QtCore/QTimer> + +#include <QtGui/QMenu> +#include <QtGui/QLabel> +#include <QtGui/QLayout> +#include <QtGui/QPrinter> +#include <QtGui/QLineEdit> +#include <QtGui/QCheckBox> +#include <QtGui/QTabBar> +#include <QtGui/QTabWidget> +#include <QtGui/QToolButton> +#include <QtGui/QMouseEvent> +#include <QtGui/QSpacerItem> +#include <QtGui/QTextCursor> +#include <QtGui/QPrintDialog> +#include <QtGui/QApplication> +#include <QtGui/QTextDocumentFragment> +#include <QtGui/QPrintPreviewDialog> +#include <QtGui/QPageSetupDialog> + +#include <QtHelp/QHelpEngine> +#include <QtHelp/QHelpSearchEngine> + +QT_BEGIN_NAMESPACE + +namespace { + HelpViewer* helpViewerFromTabPosition(const QTabWidget *widget, const QPoint &point) + { + QTabBar *tabBar = qFindChild<QTabBar*>(widget); + for (int i = 0; i < tabBar->count(); ++i) { + if (tabBar->tabRect(i).contains(point)) + return qobject_cast<HelpViewer*>(widget->widget(i)); + } + return 0; + } + CentralWidget *staticCentralWidget = 0; +} + +FindWidget::FindWidget(QWidget *parent) + : QWidget(parent) +{ + QString system = QLatin1String("win"); + QHBoxLayout *hboxLayout = new QHBoxLayout(this); +#ifdef Q_OS_MAC + system = QLatin1String("mac"); +#else + hboxLayout->setSpacing(6); + hboxLayout->setMargin(0); +#endif + + toolClose = new QToolButton(this); + toolClose->setIcon(QIcon(QString::fromUtf8(":/trolltech/assistant/images/%1/closetab.png").arg(system))); + toolClose->setAutoRaise(true); + hboxLayout->addWidget(toolClose); + + editFind = new QLineEdit(this); + editFind->setMinimumSize(QSize(150, 0)); + connect(editFind, SIGNAL(textChanged(const QString&)), + this, SLOT(updateButtons())); + hboxLayout->addWidget(editFind); + + toolPrevious = new QToolButton(this); + toolPrevious->setAutoRaise(true); + toolPrevious->setText(tr("Previous")); + toolPrevious->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + toolPrevious->setIcon(QIcon(QString::fromUtf8(":/trolltech/assistant/images/%1/previous.png").arg(system))); + hboxLayout->addWidget(toolPrevious); + + toolNext = new QToolButton(this); + toolNext->setAutoRaise(true); + toolNext->setText(tr("Next")); + toolNext->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + toolNext->setIcon(QIcon(QString::fromUtf8(":/trolltech/assistant/images/%1/next.png").arg(system))); + 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->setMinimumSize(QSize(0, 20)); + labelWrapped->setMaximumSize(QSize(105, 20)); + labelWrapped->setTextFormat(Qt::RichText); + labelWrapped->setScaledContents(true); + 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() +{ +} + +void FindWidget::updateButtons() +{ + if (editFind->text().isEmpty()) { + toolPrevious->setEnabled(false); + toolNext->setEnabled(false); + } else { + toolPrevious->setEnabled(true); + toolNext->setEnabled(true); + } +} + + +CentralWidget::CentralWidget(QHelpEngine *engine, MainWindow *parent) + : QWidget(parent) + , findBar(0) + , tabWidget(0) + , helpEngine(engine) + , printer(0) + , m_searchWidget(0) +{ + staticCentralWidget = this; + + lastTabPage = 0; + globalActionList.clear(); + collectionFile = helpEngine->collectionFile(); + usesDefaultCollection = parent->usesDefaultCollection(); + + QString system = QLatin1String("win"); + QVBoxLayout *vboxLayout = new QVBoxLayout(this); + +#ifdef Q_OS_MAC + system = QLatin1String("mac"); +#else + vboxLayout->setMargin(0); +#endif + + tabWidget = new QTabWidget(this); + connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(currentPageChanged(int))); + + QToolButton *newTabButton = new QToolButton(this); + newTabButton->setAutoRaise(true); + newTabButton->setToolTip(tr("Add new page")); + newTabButton->setIcon(QIcon(QString::fromUtf8(":/trolltech/assistant/images/%1/addtab.png").arg(system))); + + tabWidget->setCornerWidget(newTabButton, Qt::TopLeftCorner); + connect(newTabButton, SIGNAL(clicked()), this, SLOT(newTab())); + + QToolButton *closeTabButton = new QToolButton(this); + closeTabButton->setEnabled(false); + closeTabButton->setAutoRaise(true); + closeTabButton->setToolTip(tr("Close current page")); + closeTabButton->setIcon(QIcon(QString::fromUtf8(":/trolltech/assistant/images/%1/closetab.png").arg(system))); + + tabWidget->setCornerWidget(closeTabButton, Qt::TopRightCorner); + connect(closeTabButton, SIGNAL(clicked()), this, SLOT(closeTab())); + + 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(const QString&)), this, SLOT(findCurrentText(const QString&))); + connect(findWidget->toolPrevious, SIGNAL(clicked()), this, SLOT(findPrevious())); + + QTabBar *tabBar = qFindChild<QTabBar*>(tabWidget); + if (tabBar) { + tabBar->installEventFilter(this); + tabBar->setContextMenuPolicy(Qt::CustomContextMenu); + connect(tabBar, SIGNAL(customContextMenuRequested(const QPoint&)), + this, SLOT(showTabBarContextMenu(const QPoint&))); + } + + QPalette p = qApp->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)); + qApp->setPalette(p); +} + +CentralWidget::~CentralWidget() +{ + QHelpEngineCore engine(collectionFile, 0); + if (!engine.setupData()) + return; + + QString zoomCount; + QString currentPages; + QLatin1Char sep('|'); + for (int i = 1; i < tabWidget->count(); ++i) { + HelpViewer *viewer = qobject_cast<HelpViewer*>(tabWidget->widget(i)); + if (viewer && viewer->source().isValid()) { + currentPages.append(viewer->source().toString()).append(sep); +#if !defined(QT_NO_WEBKIT) + zoomCount.append(QString::number(viewer->textSizeMultiplier())). + append(sep); +#else + zoomCount.append(QString::number(viewer->zoom())).append(sep); +#endif + } + } + engine.setCustomValue(QLatin1String("LastTabPage"), lastTabPage); + engine.setCustomValue(QLatin1String("LastShownPages"), currentPages); +#if !defined(QT_NO_WEBKIT) + engine.setCustomValue(QLatin1String("LastPagesZoomWebView"), zoomCount); +#else + engine.setCustomValue(QLatin1String("LastPagesZoomTextBrowser"), zoomCount); +#endif +} + +CentralWidget *CentralWidget::instance() +{ + return staticCentralWidget; +} + +void CentralWidget::newTab() +{ + HelpViewer* viewer = currentHelpViewer(); + if (viewer) + setSourceInNewTab(viewer->source()); +} + +void CentralWidget::zoomIn() +{ + HelpViewer* viewer = currentHelpViewer(); + if (viewer) + viewer->zoomIn(); + + if (tabWidget->currentWidget() == m_searchWidget) + m_searchWidget->zoomIn(); +} + +void CentralWidget::zoomOut() +{ + HelpViewer* viewer = currentHelpViewer(); + if (viewer) + viewer->zoomOut(); + + if (tabWidget->currentWidget() == m_searchWidget) + m_searchWidget->zoomOut(); +} + +void CentralWidget::findNext() +{ + find(findWidget->editFind->text(), true, false); +} + +void CentralWidget::nextPage() +{ + if(tabWidget->currentIndex() < tabWidget->count() -1) + tabWidget->setCurrentIndex(tabWidget->currentIndex() +1); + else + tabWidget->setCurrentIndex(0); +} + +void CentralWidget::resetZoom() +{ + HelpViewer* viewer = currentHelpViewer(); + if (viewer) + viewer->resetZoom(); + + if (tabWidget->currentWidget() == m_searchWidget) + m_searchWidget->resetZoom(); +} + +void CentralWidget::previousPage() +{ + int index = tabWidget->currentIndex() -1; + if(index >= 0) + tabWidget->setCurrentIndex(index); + else + tabWidget->setCurrentIndex(tabWidget->count() -1); +} + +void CentralWidget::findPrevious() +{ + find(findWidget->editFind->text(), false, true); +} + +void CentralWidget::closeTab() +{ + HelpViewer* viewer = currentHelpViewer(); + if (!viewer|| tabWidget->count() == 1) + return; + + tabWidget->removeTab(tabWidget->indexOf(viewer)); + QTimer::singleShot(0, viewer, SLOT(deleteLater())); +} + +void CentralWidget::setSource(const QUrl &url) +{ + HelpViewer* viewer = currentHelpViewer(); + HelpViewer* lastViewer = qobject_cast<HelpViewer*>(tabWidget->widget(lastTabPage)); + + if (!viewer && !lastViewer) { + viewer = new HelpViewer(helpEngine, this); + viewer->installEventFilter(this); + lastTabPage = tabWidget->addTab(viewer, QString()); + tabWidget->setCurrentIndex(lastTabPage); + connectSignals(); + } else + viewer = lastViewer; + + viewer->setSource(url); + currentPageChanged(lastTabPage); + viewer->setFocus(Qt::OtherFocusReason); + tabWidget->setCurrentIndex(lastTabPage); + tabWidget->setTabText(lastTabPage, quoteTabTitle(viewer->documentTitle())); +} + +void CentralWidget::setLastShownPages() +{ +#if !defined(QT_NO_WEBKIT) + QLatin1String zoom("LastPagesZoomWebView"); +#else + QLatin1String zoom("LastPagesZoomTextBrowser"); +#endif + + const QStringList lastShownPageList = + helpEngine->customValue(QLatin1String("LastShownPages")).toString(). + split(QLatin1Char('|'), QString::SkipEmptyParts); + + if (!lastShownPageList.isEmpty()) { + QVector<QString>zoomList = helpEngine->customValue(zoom).toString(). + split(QLatin1Char('|'), QString::SkipEmptyParts).toVector(); + if (zoomList.isEmpty()) + zoomList.fill(QLatin1String("0.0"), lastShownPageList.size()); + else if(zoomList.count() < lastShownPageList.count()) { + zoomList.insert(zoomList.count(), + lastShownPageList.count() - zoomList.count(), QLatin1String("0.0")); + } + + QVector<QString>::const_iterator zIt = zoomList.constBegin(); + QStringList::const_iterator it = lastShownPageList.constBegin(); + for (; it != lastShownPageList.constEnd(); ++it, ++zIt) + setSourceInNewTab((*it), (*zIt).toFloat()); + + tabWidget->setCurrentIndex(helpEngine->customValue( + QLatin1String("LastTabPage"), 1).toInt()); + } else { + if (usesDefaultCollection) + setSource(QUrl(QLatin1String("help"))); + } +} + +bool CentralWidget::hasSelection() const +{ + const HelpViewer* viewer = currentHelpViewer(); + return viewer ? viewer->hasSelection() : false; +} + +QUrl CentralWidget::currentSource() const +{ + const HelpViewer* viewer = currentHelpViewer(); + if (viewer) + return viewer->source(); + + return QUrl(); +} + +QString CentralWidget::currentTitle() const +{ + const HelpViewer* viewer = currentHelpViewer(); + if (viewer) + return viewer->documentTitle(); + + return QString(); +} + +void CentralWidget::copySelection() +{ + HelpViewer* viewer = currentHelpViewer(); + if (viewer) + viewer->copy(); +} + +void CentralWidget::showTextSearch() +{ + findBar->show(); + findWidget->editFind->selectAll(); + findWidget->editFind->setFocus(Qt::ShortcutFocusReason); +} + +void CentralWidget::initPrinter() +{ +#ifndef QT_NO_PRINTER + if (!printer) + printer = new QPrinter(QPrinter::HighResolution); +#endif +} + +void CentralWidget::print() +{ +#ifndef QT_NO_PRINTER + HelpViewer* viewer = currentHelpViewer(); + if (!viewer) + return; + + initPrinter(); + + QPrintDialog *dlg = new QPrintDialog(printer, this); +#if defined(QT_NO_WEBKIT) + if (viewer->textCursor().hasSelection()) + dlg->addEnabledOption(QAbstractPrintDialog::PrintSelection); +#endif + dlg->addEnabledOption(QAbstractPrintDialog::PrintPageRange); + dlg->addEnabledOption(QAbstractPrintDialog::PrintCollateCopies); + dlg->setWindowTitle(tr("Print Document")); + if (dlg->exec() == QDialog::Accepted) { + viewer->print(printer); + } + delete dlg; +#endif +} + +void CentralWidget::printPreview() +{ +#ifndef QT_NO_PRINTER + initPrinter(); + QPrintPreviewDialog preview(printer, this); + connect(&preview, SIGNAL(paintRequested(QPrinter *)), SLOT(printPreview(QPrinter *))); + preview.exec(); +#endif +} + +void CentralWidget::printPreview(QPrinter *p) +{ +#ifndef QT_NO_PRINTER + HelpViewer *viewer = currentHelpViewer(); + if (viewer) + viewer->print(p); +#endif +} + +void CentralWidget::pageSetup() +{ +#ifndef QT_NO_PRINTER + initPrinter(); + QPageSetupDialog dlg(printer); + dlg.exec(); +#endif +} + +bool CentralWidget::isHomeAvailable() const +{ + return currentHelpViewer() ? true : false; +} + +void CentralWidget::home() +{ + HelpViewer* viewer = currentHelpViewer(); + if (viewer) + viewer->home(); +} + +bool CentralWidget::isForwardAvailable() const +{ + const HelpViewer* viewer = currentHelpViewer(); + if (viewer) + return viewer->isForwardAvailable(); + + return false; +} + +void CentralWidget::forward() +{ + HelpViewer* viewer = currentHelpViewer(); + if (viewer) + viewer->forward(); +} + +bool CentralWidget::isBackwardAvailable() const +{ + const HelpViewer* viewer = currentHelpViewer(); + if (viewer) + return viewer->isBackwardAvailable(); + + return false; +} + +void CentralWidget::backward() +{ + HelpViewer* viewer = currentHelpViewer(); + if (viewer) + viewer->backward(); +} + + +QList<QAction*> CentralWidget::globalActions() const +{ + return globalActionList; +} + +void CentralWidget::setGlobalActions(const QList<QAction*> &actions) +{ + globalActionList = actions; +} + +void CentralWidget::setSourceInNewTab(const QUrl &url, qreal zoom) +{ + HelpViewer* viewer; + +#if defined(QT_NO_WEBKIT) + viewer = currentHelpViewer(); + if (viewer && viewer->launchedWithExternalApp(url)) + return; +#endif + + viewer = new HelpViewer(helpEngine, this); + viewer->installEventFilter(this); + viewer->setSource(url); + viewer->setFocus(Qt::OtherFocusReason); + tabWidget->setCurrentIndex(tabWidget->addTab(viewer, + quoteTabTitle(viewer->documentTitle()))); + + QFont font = qApp->font(); + bool userFont = helpEngine->customValue(QLatin1String("useBrowserFont")).toBool(); + if (userFont) { + font = qVariantValue<QFont>(helpEngine->customValue( + QLatin1String("browserFont"))); + } + +#if !defined(QT_NO_WEBKIT) + QWebSettings* settings = QWebSettings::globalSettings(); + if (!userFont) { + int fontSize = settings->fontSize(QWebSettings::DefaultFontSize); + QString fontFamily = settings->fontFamily(QWebSettings::StandardFont); + font = QFont(fontFamily, fontSize); + } + + QWebView* view = qobject_cast<QWebView*> (viewer); + if (view) { + settings = view->settings(); + settings->setFontFamily(QWebSettings::StandardFont, font.family()); + settings->setFontSize(QWebSettings::DefaultFontSize, font.pointSize()); + } else if (viewer) { + viewer->setFont(font); + } + viewer->setTextSizeMultiplier(zoom == 0.0 ? 1.0 : zoom); +#else + font.setPointSize((int)(font.pointSize() + zoom)); + viewer->setFont(font); + viewer->setZoom((int)zoom); +#endif + + connectSignals(); +} + +HelpViewer *CentralWidget::newEmptyTab() +{ + HelpViewer* viewer = new HelpViewer(helpEngine, this); + viewer->installEventFilter(this); + viewer->setFocus(Qt::OtherFocusReason); +#if defined(QT_NO_WEBKIT) + viewer->setDocumentTitle(tr("unknown")); +#endif + tabWidget->setCurrentIndex(tabWidget->addTab(viewer, tr("unknown"))); + + connectSignals(); + return viewer; +} + +void CentralWidget::findCurrentText(const QString &text) +{ + find(text, false, false); +} + +void CentralWidget::connectSignals() +{ + const HelpViewer* viewer = currentHelpViewer(); + if (viewer) { + connect(viewer, SIGNAL(copyAvailable(bool)), this, SIGNAL(copyAvailable(bool))); + connect(viewer, SIGNAL(forwardAvailable(bool)), this, SIGNAL(forwardAvailable(bool))); + connect(viewer, SIGNAL(backwardAvailable(bool)), this, SIGNAL(backwardAvailable(bool))); + connect(viewer, SIGNAL(sourceChanged(const QUrl&)), this, SIGNAL(sourceChanged(const QUrl&))); + connect(viewer, SIGNAL(highlighted(const QString&)), this, SIGNAL(highlighted(const QString&))); + + connect(viewer, SIGNAL(sourceChanged(const QUrl&)), this, SLOT(setTabTitle(const QUrl&))); + } +} + +HelpViewer *CentralWidget::currentHelpViewer() const +{ + return qobject_cast<HelpViewer*>(tabWidget->currentWidget()); +} + +void CentralWidget::activateTab(bool onlyHelpViewer) +{ + if (currentHelpViewer()) { + currentHelpViewer()->setFocus(); + } else { + int idx = 0; + if (onlyHelpViewer) + idx = lastTabPage; + tabWidget->setCurrentIndex(idx); + tabWidget->currentWidget()->setFocus(); + } +} + +void CentralWidget::setTabTitle(const QUrl& url) +{ + int tab = lastTabPage; + HelpViewer* viewer = currentHelpViewer(); + +#if !defined(QT_NO_WEBKIT) + if (!viewer || viewer->source() != url) { + QTabBar *tabBar = qFindChild<QTabBar*>(tabWidget); + for (tab = 0; tab < tabBar->count(); ++tab) { + viewer = qobject_cast<HelpViewer*>(tabWidget->widget(tab)); + if (viewer && viewer->source() == url) + break; + } + } +#else + Q_UNUSED(url) +#endif + + if (viewer) { + tabWidget->setTabText(tab, + quoteTabTitle(viewer->documentTitle().trimmed())); + } +} + +void CentralWidget::currentPageChanged(int index) +{ + const HelpViewer *viewer = currentHelpViewer(); + + if (viewer || tabWidget->count() == 1) + lastTabPage = index; + + bool enabled = false; + if (viewer) { + enabled = true; + if (!m_searchWidget) + enabled = tabWidget->count() > 1; + } + + tabWidget->cornerWidget(Qt::TopRightCorner)->setEnabled(enabled); + tabWidget->cornerWidget(Qt::TopLeftCorner)->setEnabled(m_searchWidget ? enabled : true); + + emit currentViewerChanged(); +} + +void CentralWidget::showTabBarContextMenu(const QPoint &point) +{ + HelpViewer* viewer = helpViewerFromTabPosition(tabWidget, point); + if (!viewer) + return; + + QTabBar *tabBar = qFindChild<QTabBar*>(tabWidget); + + QMenu menu(QLatin1String(""), tabBar); + QAction *new_page = menu.addAction(tr("Add New Page")); + QAction *close_page = menu.addAction(tr("Close This Page")); + QAction *close_pages = menu.addAction(tr("Close Other Pages")); + menu.addSeparator(); + QAction *newBookmark = menu.addAction(tr("Add Bookmark for this Page...")); + + if (tabBar->count() == 1) { + close_page->setEnabled(false); + close_pages->setEnabled(false); + } else if (m_searchWidget && tabBar->count() == 2) { + close_pages->setEnabled(false); + } + + QAction *picked_action = menu.exec(tabBar->mapToGlobal(point)); + if (!picked_action) + return; + + if (picked_action == new_page) + setSourceInNewTab(viewer->source()); + + if (picked_action == close_page) { + tabWidget->removeTab(tabWidget->indexOf(viewer)); + QTimer::singleShot(0, viewer, SLOT(deleteLater())); + } + + if (picked_action == close_pages) { + int currentPage = tabWidget->indexOf(viewer); + for (int i = tabBar->count() -1; i >= 0; --i) { + viewer = qobject_cast<HelpViewer*>(tabWidget->widget(i)); + if (i != currentPage && viewer) { + tabWidget->removeTab(i); + QTimer::singleShot(0, viewer, SLOT(deleteLater())); + + if (i < currentPage) + --currentPage; + } + } + } + + if (picked_action == newBookmark) + emit addNewBookmark(viewer->documentTitle(), viewer->source().toString()); +} + +bool CentralWidget::eventFilter(QObject *object, QEvent *e) +{ + if (currentHelpViewer() == object && e->type() == QEvent::KeyPress){ + QKeyEvent *ke = static_cast<QKeyEvent*>(e); + if (ke->key() == Qt::Key_Backspace) { + HelpViewer *viewer = currentHelpViewer(); +#if defined(QT_NO_WEBKIT) + if (viewer && viewer->isBackwardAvailable()) { +#else + if (viewer && viewer->isBackwardAvailable() && !viewer->hasFocus()) { +#endif + viewer->backward(); + return true; + } + } + } + + QTabBar *tabBar = qobject_cast<QTabBar*>(object); + bool mousRel = e->type() == QEvent::MouseButtonRelease; + bool dblClick = e->type() == QEvent::MouseButtonDblClick; + + if (tabBar && (mousRel || dblClick)) { + QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(e); + HelpViewer *viewer = helpViewerFromTabPosition(tabWidget, mouseEvent->pos()); + if (!m_searchWidget && tabWidget->count() <= 1) + return QWidget::eventFilter(object, e); + + if (viewer && (mouseEvent->button() == Qt::MidButton || dblClick)) { + tabWidget->removeTab(tabWidget->indexOf(viewer)); + QTimer::singleShot(0, viewer, SLOT(deleteLater())); + currentPageChanged(tabWidget->currentIndex()); + return true; + } + } else if (object == findWidget->editFind && e->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast<QKeyEvent*>(e); + if (ke->key() == Qt::Key_Escape) { + findBar->hide(); + HelpViewer *hv = currentHelpViewer(); + if (hv) + hv->setFocus(); + } + } + return QWidget::eventFilter(object, e); +} + +void CentralWidget::keyPressEvent(QKeyEvent *e) +{ + QString text = e->text(); + if (text.startsWith(QLatin1Char('/'))) { + if (!findBar->isVisible()) { + findBar->show(); + findWidget->editFind->clear(); + } else { + findWidget->editFind->selectAll(); + } + findWidget->editFind->setFocus(); + return; + } + QWidget::keyPressEvent(e); +} + +void CentralWidget::find(QString ttf, bool forward, bool backward) +{ + QTextCursor cursor; + QTextDocument *doc = 0; + QTextBrowser *browser = 0; + + HelpViewer* viewer = currentHelpViewer(); + QPalette p = findWidget->editFind->palette(); + p.setColor(QPalette::Active, QPalette::Base, Qt::white); + +#if !defined(QT_NO_WEBKIT) + Q_UNUSED(forward) + Q_UNUSED(doc) + Q_UNUSED(browser) + + if (viewer) { + QWebPage::FindFlags options; + if (backward) + options |= QWebPage::FindBackward; + + if (findWidget->checkCase->isChecked()) + options |= QWebPage::FindCaseSensitively; + + bool found = viewer->findText(ttf, options); + findWidget->labelWrapped->hide(); + + if (!found) { + options |= QWebPage::FindWrapsAroundDocument; + found = viewer->findText(ttf, options); + + if (!found) { + p.setColor(QPalette::Active, QPalette::Base, QColor(255, 102, 102)); + } else { + findWidget->labelWrapped->show(); + } + } + } +#else + if (viewer) { + doc = viewer->document(); + cursor = viewer->textCursor(); + browser = qobject_cast<QTextBrowser*>(viewer); + } + + if (tabWidget->currentWidget() == m_searchWidget) { + QTextBrowser* browser = qFindChild<QTextBrowser*>(m_searchWidget); + if (browser) { + doc = browser->document(); + cursor = browser->textCursor(); + } + } + + if (!browser || !doc || cursor.isNull()) + return; + + QTextDocument::FindFlags options; + + if (cursor.hasSelection()) + cursor.setPosition(forward ? cursor.position() : cursor.anchor(), QTextCursor::MoveAnchor); + + QTextCursor newCursor = cursor; + + if (!ttf.isEmpty()) { + if (backward) + options |= QTextDocument::FindBackward; + + if (findWidget->checkCase->isChecked()) + options |= QTextDocument::FindCaseSensitively; + + if (findWidget->checkWholeWords->isChecked()) + options |= QTextDocument::FindWholeWords; + + newCursor = doc->find(ttf, cursor, options); + findWidget->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 = cursor; + } else { + findWidget->labelWrapped->show(); + } + } + } +#endif + + if (!findWidget->isVisible()) + findWidget->show(); + +#if defined(QT_NO_WEBKIT) + if (browser) + browser->setTextCursor(newCursor); +#endif + findWidget->editFind->setPalette(p); +} + +void CentralWidget::activateSearch() +{ + if (tabWidget->widget(0) != m_searchWidget) + createSearchWidget(helpEngine->searchEngine()); + + tabWidget->setCurrentWidget(m_searchWidget); + m_searchWidget->setFocus(); +} + +void CentralWidget::updateBrowserFont() +{ + QFont font = qApp->font(); + bool userFont = helpEngine->customValue(QLatin1String("useBrowserFont")).toBool(); + if (userFont) { + font = qVariantValue<QFont>(helpEngine->customValue( + QLatin1String("browserFont"))); + } + +#if !defined(QT_NO_WEBKIT) + QWebSettings* settings = QWebSettings::globalSettings(); + if (!userFont) { + int fontSize = settings->fontSize(QWebSettings::DefaultFontSize); + QString fontFamily = settings->fontFamily(QWebSettings::StandardFont); + font = QFont(fontFamily, fontSize); + } +#endif + + QWidget* widget = 0; + for (int i = 0; i < tabWidget->count(); ++i) { + widget = tabWidget->widget(i); +#if !defined(QT_NO_WEBKIT) + QWebView* view = qobject_cast<QWebView*> (widget); + if (view) { + settings = view->settings(); + settings->setFontFamily(QWebSettings::StandardFont, font.family()); + settings->setFontSize(QWebSettings::DefaultFontSize, font.pointSize()); + } else if (widget) { + if (!userFont) + font = qApp->font(); + widget->setFont(font); + } +#else + if (widget && widget->font() != font) + widget->setFont(font); +#endif + } +} + +void CentralWidget::createSearchWidget(QHelpSearchEngine *searchEngine) +{ + if (!m_searchWidget) { + m_searchWidget = new SearchWidget(searchEngine, this); + connect(m_searchWidget, SIGNAL(requestShowLink(const QUrl&)), this, + SLOT(setSourceFromSearch(const QUrl&))); + connect(m_searchWidget, SIGNAL(requestShowLinkInNewTab(const QUrl&)), this, + SLOT(setSourceFromSearchInNewTab(const QUrl&))); + } + tabWidget->insertTab(0, m_searchWidget, tr("Search")); +} + +void CentralWidget::removeSearchWidget() +{ + tabWidget->removeTab(0); +} + +QString CentralWidget::quoteTabTitle(const QString &title) const +{ + QString s = title; + return s.replace(QLatin1Char('&'), QLatin1String("&&")); +} + +void +CentralWidget::setSourceFromSearch(const QUrl &url) +{ + setSource(url); + highlightSearchTerms(); +} + +void +CentralWidget::setSourceFromSearchInNewTab(const QUrl &url) +{ + setSourceInNewTab(url); + highlightSearchTerms(); +} + +void +CentralWidget::highlightSearchTerms() +{ +#if defined(QT_NO_WEBKIT) + HelpViewer *viewer = currentHelpViewer(); + if (!viewer) + return; + + QHelpSearchEngine* searchEngine = helpEngine->searchEngine(); + QList<QHelpSearchQuery> queryList = searchEngine->query(); + + QStringList terms; + foreach (QHelpSearchQuery query, queryList) { + switch (query.fieldName) { + default: break; + case QHelpSearchQuery::ALL: { + case QHelpSearchQuery::PHRASE: + case QHelpSearchQuery::DEFAULT: + case QHelpSearchQuery::ATLEAST: + foreach (QString term, query.wordList) + terms.append(term.remove(QLatin1String("\""))); + } + } + } + + viewer->viewport()->setUpdatesEnabled(false); + + QTextCharFormat marker; + marker.setForeground(Qt::red); + + QTextCursor firstHit; + + QTextCursor c = viewer->textCursor(); + c.beginEditBlock(); + foreach (const QString& term, terms) { + c.movePosition(QTextCursor::Start); + viewer->setTextCursor(c); + + while (viewer->find(term, QTextDocument::FindWholeWords)) { + QTextCursor hit = viewer->textCursor(); + if (firstHit.isNull() || hit.position() < firstHit.position()) + firstHit = hit; + + hit.mergeCharFormat(marker); + } + } + + if (firstHit.isNull()) { + firstHit = viewer->textCursor(); + firstHit.movePosition(QTextCursor::Start); + } + firstHit.clearSelection(); + c.endEditBlock(); + viewer->setTextCursor(firstHit); + + viewer->viewport()->setUpdatesEnabled(true); +#endif +} + +void CentralWidget::closeTabAt(int index) +{ + HelpViewer *viewer = qobject_cast<HelpViewer*>(tabWidget->widget(index)); + tabWidget->removeTab(index); + QTimer::singleShot(0, viewer, SLOT(deleteLater())); +} + +QMap<int, QString> CentralWidget::currentSourceFileList() const +{ + QMap<int, QString> sourceList; + for (int i = 1; i < tabWidget->count(); ++i) { + HelpViewer *viewer = qobject_cast<HelpViewer*>(tabWidget->widget(i)); + if (viewer && viewer->source().isValid()) + sourceList.insert(i, viewer->source().host()); + } + return sourceList; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/centralwidget.h b/tools/assistant/tools/assistant/centralwidget.h new file mode 100644 index 0000000..75bd8be --- /dev/null +++ b/tools/assistant/tools/assistant/centralwidget.h @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CENTRALWIDGET_H +#define CENTRALWIDGET_H + +#include <QtCore/QUrl> +#include <QtCore/QPoint> +#include <QtCore/QObject> + +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE + +class QEvent; +class QLabel; +class QAction; +class QCheckBox; +class QLineEdit; +class QToolButton; + +class HelpViewer; +class QTabWidget; +class QHelpEngine; +class CentralWidget; +class PrintHelper; +class MainWindow; + +class SearchWidget; +class QHelpSearchEngine; + +class FindWidget : public QWidget +{ + Q_OBJECT + +public: + FindWidget(QWidget *parent = 0); + ~FindWidget(); + +signals: + void findNext(); + void findPrevious(); + +private slots: + void updateButtons(); + +private: + QLineEdit *editFind; + QCheckBox *checkCase; + QLabel *labelWrapped; + QToolButton *toolNext; + QToolButton *toolClose; + QToolButton *toolPrevious; + QCheckBox *checkWholeWords; + + friend class CentralWidget; +}; + +class CentralWidget : public QWidget +{ + Q_OBJECT + +public: + CentralWidget(QHelpEngine *engine, MainWindow *parent); + ~CentralWidget(); + + void setLastShownPages(); + bool hasSelection() const; + QUrl currentSource() const; + QString currentTitle() const; + bool isHomeAvailable() const; + bool isForwardAvailable() const; + bool isBackwardAvailable() const; + QList<QAction*> globalActions() const; + void setGlobalActions(const QList<QAction*> &actions); + HelpViewer *currentHelpViewer() const; + void activateTab(bool onlyHelpViewer = false); + void activateSearch(); + void createSearchWidget(QHelpSearchEngine *searchEngine); + void removeSearchWidget(); + + void closeTabAt(int index); + QMap<int, QString> currentSourceFileList() const; + + static CentralWidget *instance(); + +public slots: + void zoomIn(); + void zoomOut(); + void findNext(); + void nextPage(); + void resetZoom(); + void previousPage(); + void findPrevious(); + void copySelection(); + void showTextSearch(); + void print(); + void pageSetup(); + void printPreview(); + 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(); + +signals: + void currentViewerChanged(); + void copyAvailable(bool yes); + void sourceChanged(const QUrl &url); + void highlighted(const QString &link); + void forwardAvailable(bool available); + void backwardAvailable(bool available); + void addNewBookmark(const QString &title, const QString &url); + +protected: + void keyPressEvent(QKeyEvent *); + +private slots: + void newTab(); + void closeTab(); + void setTabTitle(const QUrl& url); + void currentPageChanged(int index); + void showTabBarContextMenu(const QPoint &point); + void printPreview(QPrinter *printer); + void setSourceFromSearch(const QUrl &url); + void setSourceFromSearchInNewTab(const QUrl &url); + +private: + void connectSignals(); + bool eventFilter(QObject *object, QEvent *e); + void find(QString ttf, bool forward, bool backward); + void initPrinter(); + QString quoteTabTitle(const QString &title) const; + void highlightSearchTerms(); + +private: + int lastTabPage; + QString collectionFile; + QList<QAction*> globalActionList; + + QWidget *findBar; + QTabWidget* tabWidget; + FindWidget *findWidget; + QHelpEngine *helpEngine; + QPrinter *printer; + bool usesDefaultCollection; + + SearchWidget* m_searchWidget; +}; + +QT_END_NAMESPACE + +#endif // CENTRALWIDGET_H diff --git a/tools/assistant/tools/assistant/cmdlineparser.cpp b/tools/assistant/tools/assistant/cmdlineparser.cpp new file mode 100644 index 0000000..0dae785 --- /dev/null +++ b/tools/assistant/tools/assistant/cmdlineparser.cpp @@ -0,0 +1,320 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QFileInfo> +#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_copy(false), + m_quiet(false) +{ + m_helpMessage = QLatin1String( + "Usage: assistant [Options]\n\n" + "-collectionFile file Uses the specified collection\n" + " file instead of the default one\n" + "-showUrl url Shows the document with the\n" + " url.\n" + "-enableRemoteControl Enables Assistant to be\n" + " remotely controlled.\n" + "-show widget Shows the specified dockwidget\n" + " which can be \"contents\", \"index\",\n" + " \"bookmarks\" or \"search\".\n" + "-activate widget Activates the specified dockwidget\n" + " which can be \"contents\", \"index\",\n" + " \"bookmarks\" or \"search\".\n" + "-hide widget Hides the specified dockwidget\n" + " which can be \"contents\", \"index\"\n" + " \"bookmarks\" or \"search\".\n" + "-register helpFile Registers the specified help file\n" + " (.qch) in the given collection\n" + " file.\n" + "-unregister helpFile Unregisters the specified help file\n" + " (.qch) from the give collection\n" + " file.\n" + "-setCurrentFilter filter Set the filter as the active filter.\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")) { + m_quiet = true; + break; + } + } + + 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")) { + 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("-quiet")) { + continue; + } 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; + } + } + + if (!error.isEmpty()) { + showMessage(error + QLatin1String("\n\n\n") + m_helpMessage, true); + return Error; + } else if (showHelp) { + showMessage(m_helpMessage, false); + return Help; + } + return Ok; +} + +QString CmdLineParser::getFileName(const QString &fileName) +{ + QFileInfo fi(fileName); + if (!fi.exists()) + return QString(); + return fi.absoluteFilePath(); +} + +void CmdLineParser::showMessage(const QString &msg, bool error) +{ + if (m_quiet) + return; +#ifdef Q_OS_WIN + QString s = QLatin1String("<pre>") + msg + QLatin1String("</pre>"); + if (error) + QMessageBox::critical(0, QObject::tr("Qt Assistant"), s); + else + QMessageBox::information(0, QObject::tr("Qt Assistant"), s); +#else + fprintf(error ? stderr : stdout, "%s\n", qPrintable(msg)); +#endif +} + +void CmdLineParser::setCollectionFile(const QString &file) +{ + m_collectionFile = file; +} + +QString CmdLineParser::collectionFile() const +{ + return m_collectionFile; +} + +QUrl CmdLineParser::url() const +{ + return m_url; +} + +bool CmdLineParser::enableRemoteControl() const +{ + return m_enableRemoteControl; +} + +CmdLineParser::ShowState CmdLineParser::contents() const +{ + return m_contents; +} + +CmdLineParser::ShowState CmdLineParser::index() const +{ + return m_index; +} + +CmdLineParser::ShowState CmdLineParser::bookmarks() const +{ + return m_bookmarks; +} + +CmdLineParser::ShowState CmdLineParser::search() const +{ + return m_search; +} + +QString CmdLineParser::currentFilter() const +{ + return m_currentFilter; +} + +CmdLineParser::RegisterState CmdLineParser::registerRequest() const +{ + return m_register; +} + +QString CmdLineParser::helpFile() const +{ + return m_helpFile; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/cmdlineparser.h b/tools/assistant/tools/assistant/cmdlineparser.h new file mode 100644 index 0000000..332d464 --- /dev/null +++ b/tools/assistant/tools/assistant/cmdlineparser.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CMDLINEPARSER_H +#define CMDLINEPARSER_H + +#include <QtCore/QStringList> +#include <QtCore/QUrl> + +QT_BEGIN_NAMESPACE + +class CmdLineParser +{ +public: + enum Result {Ok, Help, Error}; + enum ShowState {Untouched, Show, Hide, Activate}; + enum RegisterState {None, Register, Unregister}; + + CmdLineParser(); + Result parse(const QStringList &arguments); + + void setCollectionFile(const QString &file); + QString collectionFile() const; + QString cloneFile() const; + QUrl url() const; + bool enableRemoteControl() const; + ShowState contents() const; + ShowState index() const; + ShowState bookmarks() const; + ShowState search() const; + QString currentFilter() 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); + + QString m_helpMessage; + QString m_collectionFile; + QString m_cloneFile; + QString m_helpFile; + QUrl m_url; + bool m_enableRemoteControl; + + ShowState m_contents; + ShowState m_index; + ShowState m_bookmarks; + ShowState m_search; + RegisterState m_register; + QString m_currentFilter; + bool m_copy; + bool m_quiet; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/tools/assistant/contentwindow.cpp b/tools/assistant/tools/assistant/contentwindow.cpp new file mode 100644 index 0000000..ef272e8 --- /dev/null +++ b/tools/assistant/tools/assistant/contentwindow.cpp @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "contentwindow.h" +#include "centralwidget.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) + , m_expandDepth(-2) +{ + m_contentWidget = m_helpEngine->contentWidget(); + m_contentWidget->viewport()->installEventFilter(this); + m_contentWidget->setContextMenuPolicy(Qt::CustomContextMenu); + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->setMargin(4); + layout->addWidget(m_contentWidget); + + connect(m_contentWidget, SIGNAL(customContextMenuRequested(QPoint)), this, + SLOT(showContextMenu(QPoint))); + connect(m_contentWidget, SIGNAL(linkActivated(QUrl)), this, + SIGNAL(linkActivated(QUrl))); + + QHelpContentModel *contentModel = + qobject_cast<QHelpContentModel*>(m_contentWidget->model()); + connect(contentModel, SIGNAL(contentsCreated()), this, SLOT(expandTOC())); +} + +ContentWindow::~ContentWindow() +{ +} + +bool ContentWindow::syncToContent(const QUrl& url) +{ + QModelIndex idx = m_contentWidget->indexOf(url); + if (!idx.isValid()) + return false; + m_contentWidget->setCurrentIndex(idx); + return true; +} + +void ContentWindow::expandTOC() +{ + if (m_expandDepth > -2) { + expandToDepth(m_expandDepth); + m_expandDepth = -2; + } +} + +void ContentWindow::expandToDepth(int depth) +{ + m_expandDepth = depth; + if (depth == -1) + m_contentWidget->expandAll(); + else + m_contentWidget->expandToDepth(depth); +} + +void ContentWindow::focusInEvent(QFocusEvent *e) +{ + if (e->reason() != Qt::MouseFocusReason) + m_contentWidget->setFocus(); +} + +void ContentWindow::keyPressEvent(QKeyEvent *e) +{ + if (e->key() == Qt::Key_Escape) + emit escapePressed(); +} + +bool ContentWindow::eventFilter(QObject *o, QEvent *e) +{ + if (m_contentWidget && o == m_contentWidget->viewport() && e->type() + == QEvent::MouseButtonRelease) { + QMouseEvent *me = static_cast<QMouseEvent*>(e); + if (m_contentWidget->indexAt(me->pos()).isValid() + && me->button() == Qt::LeftButton) { + itemClicked(m_contentWidget->currentIndex()); + } else if (m_contentWidget->indexAt(me->pos()).isValid() + && me->button() == Qt::MidButton) { + QHelpContentModel *contentModel = + qobject_cast<QHelpContentModel*>(m_contentWidget->model()); + QHelpContentItem *itm = + contentModel->contentItemAt(m_contentWidget->currentIndex()); + CentralWidget::instance()->setSourceInNewTab(itm->url()); + } + } + return QWidget::eventFilter(o, e); +} + +void ContentWindow::showContextMenu(const QPoint &pos) +{ + if (!m_contentWidget->indexAt(pos).isValid()) + return; + + QMenu menu; + QAction *curTab = menu.addAction(tr("Open Link")); + QAction *newTab = menu.addAction(tr("Open Link in New Tab")); + menu.move(m_contentWidget->mapToGlobal(pos)); + + QHelpContentModel *contentModel = + qobject_cast<QHelpContentModel*>(m_contentWidget->model()); + QHelpContentItem *itm = + contentModel->contentItemAt(m_contentWidget->currentIndex()); + + QAction *action = menu.exec(); + if (curTab == action) + emit linkActivated(itm->url()); + else if (newTab == action) + CentralWidget::instance()->setSourceInNewTab(itm->url()); +} + +void ContentWindow::itemClicked(const QModelIndex &index) +{ + if (!index.isValid()) + return; + QHelpContentModel *contentModel = + qobject_cast<QHelpContentModel*>(m_contentWidget->model()); + QHelpContentItem *itm = + contentModel->contentItemAt(index); + if (itm) + emit linkActivated(itm->url()); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/contentwindow.h b/tools/assistant/tools/assistant/contentwindow.h new file mode 100644 index 0000000..ab8f8dd --- /dev/null +++ b/tools/assistant/tools/assistant/contentwindow.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CONTENTWINDOW_H +#define CONTENTWINDOW_H + +#include <QtCore/QUrl> +#include <QtCore/QModelIndex> +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE + +class QHelpEngine; +class QHelpContentWidget; + +class ContentWindow : public QWidget +{ + Q_OBJECT + +public: + ContentWindow(QHelpEngine *helpEngine); + ~ContentWindow(); + + bool syncToContent(const QUrl &url); + void expandToDepth(int depth); + +signals: + void linkActivated(const QUrl &link); + void escapePressed(); + +private slots: + void showContextMenu(const QPoint &pos); + void expandTOC(); + void itemClicked(const QModelIndex &index); + +private: + void focusInEvent(QFocusEvent *e); + void keyPressEvent(QKeyEvent *e); + bool eventFilter(QObject *o, QEvent *e); + + QHelpEngine *m_helpEngine; + QHelpContentWidget *m_contentWidget; + int m_expandDepth; +}; + +QT_END_NAMESPACE + +#endif // CONTENTWINDOW_H diff --git a/tools/assistant/tools/assistant/doc/HOWTO b/tools/assistant/tools/assistant/doc/HOWTO new file mode 100644 index 0000000..0e5b67b --- /dev/null +++ b/tools/assistant/tools/assistant/doc/HOWTO @@ -0,0 +1,17 @@ +How to build/ update a new assistant.qch for Assistant internal help + +- in case of update: + - open assistant.qdocconf, update year and qt version + +- all other cases: + - ..\..\..\..\qdoc3\debug\qdoc3.exe assistant.qdocconf + will generate an folder html containing all required stuff + + - cp assistant.qhp to generated html folder + - run qhelpgenerator html\assistant.qhp -o ..\assistant.qch + + - rebuild assistant + +- to test you changes: + - remove assistant.qch in your cache directory + - restart assistant diff --git a/tools/assistant/tools/assistant/doc/assistant.qdoc b/tools/assistant/tools/assistant/doc/assistant.qdoc new file mode 100644 index 0000000..0d13490 --- /dev/null +++ b/tools/assistant/tools/assistant/doc/assistant.qdoc @@ -0,0 +1,434 @@ +/*! + \page assistant.html + \title Qt Assistant + + \chapter Introduction + + This document introduces \e{Qt Assistant}, a tool for presenting on-line + documentation. It also introduces the Qt Reference Documentation which + is accessible using \e{Qt Assistant}, or with a web browser. The document is + divided into the following sections: + + Table of contents: + + \list + \o \l{Introduction} + \o \l{The One-Minute Guide to Using Qt Assistant} + \o \l{Introduction to the Qt Reference Documentation} + \o \l{Qt Assistant in More Detail} + \o \l{Full Text Searching} + \endlist + + \chapter The One-Minute Guide to Using Qt Assistant + + Once you have installed Qt, \QA should be ready to run: + + \list + \o On Windows, \QA is available as a menu option on the Qt menu. + \o On Mac OS X, \QA is installed in the /Developer/Applications/Qt directory. + \o On Unix/Linux, open a terminal, type \c{assistant} and press \key{Enter}. + \endlist + + When you start up \QA, you will be presented with a standard main window + application, with a menu bar and toolbar. Below these, on the left hand + side are navigation windows called \e{Contents}, \e{Index} and \e{Bookmarks}. + On the right, taking up most of the space, is the \e{Documentation} window. + By default, \QA loads the Qt reference documentation along with the manuals + of other Qt tools, like \QD or \QL. + + \QA works in a similar way to a Web browser. If you click hyperlinks + (cross-references), the \e{Documentation} window will present the relevant + page. You can bookmark pages of particular interest and you can click the + \gui{Previous} and \gui{Next} toolbar buttons to navigate within the pages + you have visited. + + Although \QA can be used just like a Web browser to navigate through + the documentation, \QA offers a powerful means of navigation that Web + browsers do not provide. \QA uses an advanced full text search engine + to index all the pages in each compressed help file so that you can + search for particular words and phrases. + + To perform an index search, click the \gui{Index} tab on the Sidebar + (or press \key{Alt+I}). In the \gui{'Look For'} line edit enter a word; + e.g., 'homedirpath'. As you type, words are found and highlighted in a list + beneath the line edit. If the highlighted text matches what you're + looking for, double click it, (or press \key{Enter}) and the + \e{Documentation} window will display the relevant page. You rarely have + to type in the whole word before \QA finds a match. Note that for some + words there may be more than one possible page that is relevant. + + \QA also provides full text searching for finding specific words in + the documentation. To activate the full text search, either press \key(Alt+S) + or click on the \gui{Search} tab in the \e{Documentation} window. Then + enter the term you're looking for and hit the \gui{Search} button. All + documents containing the specified term will then be listed in the list box + below. + + \chapter Introduction to the Qt Reference Documentation + + The documentation for the Qt library is written in-line in the \c + .cpp files by the developers themselves. The documentation team + revises the documentation to ensure that it is accurate and usable, + and to provide quality control. The documentation team also writes the + larger texts, such as the class descriptions that introduce a class + along with the concepts the class uses, as well as introducing the + functions and properties that the class provides. + + The documentation focuses on the API rather than the internals, since + we make great efforts to keep our API consistent and compatible with + each new version, but we may change the internals considerably to improve + performance and enhance functionality. + + The Qt Reference Documentation consists of almost 1,500 HTML pages + (over 2,500 printed pages). The overwhelming majority of pages + document Qt classes. Since developers differ in the way they + think and work we provide a variety of approaches to navigating the + documentation set: + + \list + \i The \menu{Qt's Classes} page lists every class + in Qt's public API, and consists of several hundred classes. + \i The \menu{Qt's Main Classes} page lists the + classes you're most likely to use most often, and provides a much + shorter and more managable list than the All Classes list. + \i The \menu{Grouped Classes} page presents a list + of groups, each of which leads to a list of related classes, for + example, the \menu{Advanced Widgets} list. + \i The \menu{Class Inheritance Hierarchy} page + presents a list of classes in terms of the hierarchy of Qt classes. + \i The \menu{Member Function Index} page lists all the + functions provided by Qt classes, each one with links to the class(es) + in which it appears. + \endlist + + No matter where you find yourself in the Qt documentation, you will + find extensive cross-referencing. Even snippets of example code + contain clickable links, so that for example, if you come across a + class declaration in a code example, the class name will be a + clickable link to the class's documentation. + + In addition to the class documentation some of Qt's modules have + extensive descriptions, and there are many overview documents which + describe various aspects of the Qt library; all these are linked from + the reference documentation home page. There are also two tutorials + and numerous example programs in the examples subdirectory of the Qt + distribution. + + \chapter Qt Assistant in More Detail + + \img assistant-assistant.png + + \section1 Command Line Options + + \QA handles the following command line options: + + \table + \header + \o Command Line Option + \o Brief Description + \row + \o -collectionFile <file.qhc> + \o Uses the specified collection file instead of the default one. + \row + \o -showUrl URL + \o Shows the document referenced by URL. + \row + \o -enableRemoteControl + \o Enables \QA to be remotly controlled. + \row + \o -show <widget> + \o Shows the specified dockwidget which can be "contents", "index", + "bookmarks" or "search". + \row + \o -hide <widget> + \o Hides the specified dockwidget which can be "contents", "index", + "bookmarks" or "search. + \row + \o -activate <widget> + \o Activates the specified dockwidget which can be "contents", + "index", "bookmarks" or "search. + \row + \o -register <doc.qch> + \o Registers the specified compressed help file in the given help + collection. + \row + \o -unregister <doc.qch> + \o Unregisters the specified compressed help file from the given + collection file. + \row + \o -quiet + \o Doesn't show any error, warning or success messages. + \endtable + + \section1 Tool Windows + + \img assistant-dockwidgets.png + + The tool windows provide four ways to navigate the documentation: + + \list + \o The \gui{Contents} window presents a table of contents implemented as a + tree view for the documentation that is available. If you click an item, + its documentation will appear in the \e{Documentation} window. If you double + click an item or click on the control to the left of it, the item's sub-items + will appear. Click a sub-item to make its page appear in the \e{Documentation} + window. Click on the control next to an open item to hide its sub-items. + \o The \gui{Index} window is used to look up key words or phrases. + See \l{The One-Minute Guide to Using Qt Assistant} for how to use this + window. + \o The \gui{Bookmarks} window lists any bookmarks you have made. Double + click a bookmark to make its page appear in the \e{Documentation} window. + The \gui{Bookmarks} window provides a context menu with \gui{Show Item}, + \gui{Delete Item} as well as \gui{Rename Item}. Click in the main menu + \menu{Bookmark|Add Bookmark...} (or press \key{Ctrl+B}) to bookmark the + page that is currently showing in the \e{Documentation} window. Right click + a bookmark in the list to rename or delete the highlighted bookmark. + \endlist + + If you want the \gui{Documentation} window to use as much space as possible, + you can easily group, move or hide the tool windows. To group the windows, + drag one on top of the other and release the mouse. If one or all tool + windows are not shown, press \key{Alt+C}, \key{Alt+I} or \key{Alt+O} to show + the required window. + + The tool windows can be docked into the main window, so you can drag them + to the top, left, right or bottom of \e{Qt Assistant's} window, or you can + drag them outside \QA to float them as independent windows. + + \section1 Documentation Window + + \img assistant-docwindow.png + + The \gui{Documentation} window lets you create a tab for each + documentation page that you view. Click the \gui{Add Tab} button and a new + tab will appear with the page name as the tab's caption. This makes it + convenient to switch between pages when you are working with different + documentation. You can delete a tab by clicking the \gui{Close Tab} button + located on the right side of the \gui{Documentation} window. + + \section1 Toolbars + + \img assistant-toolbar.png + + The main toolbar provides fast access to the most common actions. + + \table + \header \o Action \o Description \o Menu Item \o Shortcut + \row \o \gui{Previous} \o Takes you to the previous page in the history. + \o \menu{Go|Previous} \o \key{Alt+Left Arrow} + \row \o \gui{Next} \o Takes you to the next page in the history. + \o \menu{Go|Next} \o \key{Alt+Right Arrow} + \row \o \gui{Home} + \o Takes you to the home page as specified in the Preferences Dialog. + \o \menu{Go|Home} \o \key{Ctrl+Home}. + \row \o \gui{Sync with Table of Contents} + \o Synchronizes the \gui{Contents} tool window with the page currently + shown in the \gui{Documentation} window. + \o \menu{Go|Sync with Table of Contents} \o + \row \o \gui{Copy} \o Copies any selected text to the clipboard. + \o \menu{Edit|Copy} \o \key{Ctrl+C} + \row \o \gui{Print} \o Opens the \gui{Print} dialog. + \o \menu{File|Print} \o \key{Ctrl+P} + \row \o \gui{Find in Text} \o Opens the \gui{Find Text} dialog. + \o \menu{Edit|Find in Text} \o \key{Ctrl+F} + \row \o \gui{Zoom in} + \o Increases the font size used to display text in the current tab. + \o \menu{View|Zoom in} \o \key{Ctrl++} + \row \o \gui{Zoom out} + \o Decreases the font size used to display text in the current tab. + \o \menu{View|Zoom out} \o \key{Ctrl+-} + \row \o \gui{Normal Size} + \o Resets the font size to its normal size in the current tab. + \o \menu{View|Normal Size} \o \key{Ctrl+0} + \endtable + + \img assistant-address-toolbar.png + + The address toolbar provides a fast way to enter a specific URL for a + documentation file. By default, the address toolbar is not shown, so it + has to be activated via \menu{View|Toolbars|Address Toolbar}. + + \img assistant-filter-toolbar.png + + The filter toolbar allows you to apply a filter to the currently installed + documentation. As with the address toolbar, the filter toolbar is not visible + by default and has to be activated via \menu{View|Toolbars|Filter Toolbar}. + + \section1 Menus + + \section2 File Menu + + \list + \o \menu{File|Page Setup...} invokes a dialog allowing you to define + page layout properties, such as margin sizes, page orientation and paper size. + \o \menu{File|Print Preview...} provides a preview of the printed pages. + \o \menu{File|Print...} opens the \l{#Print Dialog}{\gui{Print} dialog}. + \o \menu{File|New Tab} opens a new empty tab in the \gui{Documentation} + window. + \o \menu{File|Close Tab} closes the current tab of the + \gui{Documentation} window. + \o \menu{File|Exit} closes the \QA application. + \endlist + + \section2 Edit Menu + + \list + \o \menu{Edit|Copy} copies any selected text to the clipboard. + \o \menu{Edit|Find in Text} invokes the \l{#Find Text Control}{\gui{Find Text} + control} at the lower end of the \gui{Documentation} window. + \o \menu{Edit|Find Next} looks for the next occurance of the specified + text in the \gui{Find Text} control. + \o \menu{Edit|Find Previous} looks for the previous occurance of + the specified text in the \l{#Find Text Control}{\gui{Find Text} control}. + \o \menu{Edit|Preferences} invokes the \l{#Preferences Dialog}{\gui{Preferences} dialog}. + \endlist + + \section2 View Menu + + \list + \o \menu{View|Zoom in} increases the font size in the current tab. + \o \menu{View|Zoom out} decreases the font size in the current tab. + \o \menu{View|Normal Size} resets the font size in the current tab. + \o \menu{View|Contents} toggles the display of the \gui{Contents} tool window. + \o \menu{View|Index} toggles the display of the \gui{Index} tool window. + \o \menu{View|Bookmarks} toggles the display of the \gui{Bookmarks} tool window. + \o \menu{View|Search} toggles the display of the Search in the \gui{Documentation} window. + \endlist + + \section2 Go Menu + + \list + \o \menu{Go|Home} goes to the home page. + \o \menu{Go|Back} displays the previous page in the history. + \o \menu{Go|Forward} displays the next page in the history. + \o \menu{Go|Sync with Table of Contents} syncs the \gui{Contents} tool window to the currently shown page. + \o \menu{Go|Next Page} selects the next tab in the \gui{Documentation} window. + \o \menu{Go|Previous Page} selects the previous tab in the \gui{Documentation} window. + \endlist + + \section2 Bookmarks Menu + + \list + \o \menu{Bookmarks|Add} adds the current page to the list of bookmarks. + \endlist + + \section1 Dialogs + + \section2 Print Dialog + + This dialog is platform-specific. It gives access to various printer + options and can be used to print the document shown in the current tab. + + \section2 Preferences Dialog + + \img assistant-preferences-fonts.png + + The \menu{Fonts} page allows you to change the font family and font sizes of the + browser window displaying the documentation or the application itself. + + \img assistant-preferences-filters.png + + The \menu{Filters} page lets you create and remove documentation + filters. To add a new filter, click the \gui{Add} button, specify a + filter name in the pop-up dialog and click \gui{OK}, then select + the filter attributes in the list box on the right hand side. + You can delete a filter by selecting it and clicking the \gui{Remove} + button. + + \img assistant-preferences-documentation.png + + The \menu{Documentation} page lets you install and remove compressed help + files. Click the \gui{Install} button and choose the path of the compressed + help file (*.qch) you would like to install. + To delete a help file, select a documentation set in the list and click + \gui{Remove}. + + \img assistant-preferences-options.png + + The \menu{Options} page lets you specify the homepage \QA will display when + you click the \gui{Home} button in \QA's main user interface. You can specify + the hompage by typing it here or clicking on one of the buttons below the + textbox. \gui{Current Page} sets the currently displayed page as your home + page while \gui{Restore to default} will reset your home page to the default + home page. + + \section1 Find Text Control + + This control is used to find text in the current page. Enter the text you want + to find in the line edit. The search is incremental, meaning that the most + relevant result is shown as you enter characters into the line edit. + + If you check the \gui{Whole words only} checkbox, the search will only consider + whole words; for example, if you search for "spin" with this checkbox checked it will + not match "spinbox", but will match "spin". If you check the \gui{Case sensitive} + checkbox then, for example, "spin" will match "spin" but not "Spin". You can + search forwards or backwards from your current position in the page by clicking + the \gui{Previous} or \gui{Next} buttons. To hide the find control, either click the + \gui{Close} button or hit the \key{Esc} key. + + \section1 Filtering Help Contents + + \QA allows you to install any kind of documentation as long as it is organized + in Qt compressed help files (*.qch). For example, it is possible to install the + Qt reference documentation for Qt 4.4.0 and Qt 4.4.1 at the same time. In many + respects, this is very convenient since only one version of \QA is needed. + However, at the same time it becomes more complicated when performing tasks like + searching the index because nearly every keyword is defined in Qt 4.4.0 as well + as in Qt 4.4.1. This means that \QA will always ask the user to choose which one + should be displayed. + + We use documentation filters to solve this issue. A filter is identified by its + name, and contains a list of filter attributes. An attribute is just a string and + can be freely chosen. Attributes are defined by the documentation itself, this + means that every documentation set usually has one or more attributes. + + For example, the Qt 4.4.0 \QA documentation defines the attributes \c {assistant}, + \c{tools} and \c{4.4.0}, \QD defines \c{designer}, \c{tools} and \c{4.4.0}. + The filter to display all tools would then define only the attribute + \c{tools} since this attribute is part of both documentation sets. + Adding the attribute \c{assistant} to the filter would then only show \QA + documentation since the \QD documentation does not contain this + attribute. Having an empty list of attributes in a filter will match all + documentation; i.e., it is equivalent to requesting unfiltered documentation. + + \section1 Full Text Searching + + \img assistant-search.png + + \QA provides a powerful full text search engine. To search + for certain words or text, click the \gui{Search} tab in the \gui{Documentation} + window. Then enter the text you want to look for and press \key{Enter} + or click the \gui{Search} button. The search is not case sensitive, so, + for example, Foo, fOo and FOO are all treated as the same. The following are + examples of common search patterns: + + \list + \o \c deep -- lists all the documents that contain the word 'deep' + \o \c{deep*} -- lists all the documents that contain a word beginning + with 'deep' + \o \c{deep copy} -- lists all documents that contain both 'deep' \e + and 'copy' + \o \c{"deep copy"} -- list all documents that contain the phrase 'deep copy' + \endlist + + It is also possible to use the \gui{Advanced search} to get more flexibility. + You can specify some words so that hits containing these are excluded from the + result, or you can search for an exact phrase. Searching for similar words will + give results like these: + + \list + \o \c{QStin} -- lists all the documents with titles that are similar, such as \c{QString} + \o \c{QSting} -- lists all the documents with titles that are similar, such as \c{QString} + \o \c{QStrin} -- lists all the documents with titles that are similar, such as \c{QString} + \endlist + + Options can be combined to improve the search results. + + The list of documents found is ordered according to the number of + occurrences of the search text which they contain, with those containing + the highest number of occurrences appearing first. Simply click any + document in the list to display it in the \gui{Documentation} window. + + If the documentation has changed \mdash for example, if documents have been added + or removed \mdash \QA will index them again. +*/ diff --git a/tools/assistant/tools/assistant/doc/assistant.qdocconf b/tools/assistant/tools/assistant/doc/assistant.qdocconf new file mode 100644 index 0000000..50f18c0 --- /dev/null +++ b/tools/assistant/tools/assistant/doc/assistant.qdocconf @@ -0,0 +1,17 @@ +include(../../../../qdoc3/test/qt.qdocconf) + +version = + +sourcedirs = $QTDIR/tools/assistant/tools/assistant/doc +imagedirs = $QTDIR/tools/assistant/tools/assistant/doc/images +outputdir = $QTDIR/tools/assistant/tools/assistant/doc/html +project = assistant +description = "Qt Assistant" +HTML.{postheader,address} = "" +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 © 2008 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.5.0</div></td>\n" \ + "</tr></table></div></address>" diff --git a/tools/assistant/tools/assistant/doc/assistant.qhp b/tools/assistant/tools/assistant/doc/assistant.qhp new file mode 100644 index 0000000..7a26101 --- /dev/null +++ b/tools/assistant/tools/assistant/doc/assistant.qhp @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<QtHelpProject version="1.0"> + <virtualFolder>assistant</virtualFolder> + <namespace>com.trolltech.com.assistantinternal_1.0.0</namespace> + <filterSection> + <files> + <file>assistant.html</file> + <file>classic.css</file> + <file>images/assistant-address-toolbar.png</file> + <file>images/assistant-assistant.png</file> + <file>images/assistant-dockwidgets.png</file> + <file>images/assistant-docwindow.png</file> + <file>images/assistant-filter-toolbar.png</file> + <file>images/assistant-preferences-documentation.png</file> + <file>images/assistant-preferences-filters.png</file> + <file>images/assistant-preferences-fonts.png</file> + <file>images/assistant-preferences-options.png</file> + <file>images/assistant-search.png</file> + <file>images/assistant-toolbar.png</file> + </files> + </filterSection> +</QtHelpProject> diff --git a/tools/assistant/tools/assistant/doc/classic.css b/tools/assistant/tools/assistant/doc/classic.css new file mode 100644 index 0000000..9113540 --- /dev/null +++ b/tools/assistant/tools/assistant/doc/classic.css @@ -0,0 +1,92 @@ +h3.fn,span.fn +{ + margin-left: 1cm; + text-indent: -1cm; +} + +a:link +{ + color: #004faf; + text-decoration: none +} + +a:visited +{ + color: #672967; + text-decoration: none +} + +td.postheader +{ + font-family: sans-serif +} + +tr.address +{ + font-family: sans-serif +} + +body +{ + background: #ffffff; + color: black +} + +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: none; + padding-bottom: none; + padding-left: none; + padding-right: none; + border: none; + background: none +} + +tr.qt-style +{ + background: #a2c511; + color: black +} + +body 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; +} diff --git a/tools/assistant/tools/assistant/doc/images/assistant-address-toolbar.png b/tools/assistant/tools/assistant/doc/images/assistant-address-toolbar.png Binary files differnew file mode 100644 index 0000000..847b7de --- /dev/null +++ b/tools/assistant/tools/assistant/doc/images/assistant-address-toolbar.png diff --git a/tools/assistant/tools/assistant/doc/images/assistant-assistant.png b/tools/assistant/tools/assistant/doc/images/assistant-assistant.png Binary files differnew file mode 100644 index 0000000..b825de0 --- /dev/null +++ b/tools/assistant/tools/assistant/doc/images/assistant-assistant.png diff --git a/tools/assistant/tools/assistant/doc/images/assistant-dockwidgets.png b/tools/assistant/tools/assistant/doc/images/assistant-dockwidgets.png Binary files differnew file mode 100644 index 0000000..17bc064 --- /dev/null +++ b/tools/assistant/tools/assistant/doc/images/assistant-dockwidgets.png diff --git a/tools/assistant/tools/assistant/doc/images/assistant-docwindow.png b/tools/assistant/tools/assistant/doc/images/assistant-docwindow.png Binary files differnew file mode 100644 index 0000000..c5bac58 --- /dev/null +++ b/tools/assistant/tools/assistant/doc/images/assistant-docwindow.png diff --git a/tools/assistant/tools/assistant/doc/images/assistant-examples.png b/tools/assistant/tools/assistant/doc/images/assistant-examples.png Binary files differnew file mode 100644 index 0000000..47c01bc --- /dev/null +++ b/tools/assistant/tools/assistant/doc/images/assistant-examples.png diff --git a/tools/assistant/tools/assistant/doc/images/assistant-filter-toolbar.png b/tools/assistant/tools/assistant/doc/images/assistant-filter-toolbar.png Binary files differnew file mode 100644 index 0000000..4e89a79 --- /dev/null +++ b/tools/assistant/tools/assistant/doc/images/assistant-filter-toolbar.png diff --git a/tools/assistant/tools/assistant/doc/images/assistant-preferences-documentation.png b/tools/assistant/tools/assistant/doc/images/assistant-preferences-documentation.png Binary files differnew file mode 100644 index 0000000..790fd9a --- /dev/null +++ b/tools/assistant/tools/assistant/doc/images/assistant-preferences-documentation.png diff --git a/tools/assistant/tools/assistant/doc/images/assistant-preferences-filters.png b/tools/assistant/tools/assistant/doc/images/assistant-preferences-filters.png Binary files differnew file mode 100644 index 0000000..7453dd6 --- /dev/null +++ b/tools/assistant/tools/assistant/doc/images/assistant-preferences-filters.png diff --git a/tools/assistant/tools/assistant/doc/images/assistant-preferences-fonts.png b/tools/assistant/tools/assistant/doc/images/assistant-preferences-fonts.png Binary files differnew file mode 100644 index 0000000..d42d190 --- /dev/null +++ b/tools/assistant/tools/assistant/doc/images/assistant-preferences-fonts.png diff --git a/tools/assistant/tools/assistant/doc/images/assistant-preferences-options.png b/tools/assistant/tools/assistant/doc/images/assistant-preferences-options.png Binary files differnew file mode 100644 index 0000000..d662415 --- /dev/null +++ b/tools/assistant/tools/assistant/doc/images/assistant-preferences-options.png diff --git a/tools/assistant/tools/assistant/doc/images/assistant-search.png b/tools/assistant/tools/assistant/doc/images/assistant-search.png Binary files differnew file mode 100644 index 0000000..ef75c33 --- /dev/null +++ b/tools/assistant/tools/assistant/doc/images/assistant-search.png diff --git a/tools/assistant/tools/assistant/doc/images/assistant-toolbar.png b/tools/assistant/tools/assistant/doc/images/assistant-toolbar.png Binary files differnew file mode 100644 index 0000000..1b41825 --- /dev/null +++ b/tools/assistant/tools/assistant/doc/images/assistant-toolbar.png diff --git a/tools/assistant/tools/assistant/filternamedialog.cpp b/tools/assistant/tools/assistant/filternamedialog.cpp new file mode 100644 index 0000000..fc137ed --- /dev/null +++ b/tools/assistant/tools/assistant/filternamedialog.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui/QPushButton> + +#include "filternamedialog.h" + +QT_BEGIN_NAMESPACE + +FilterNameDialog::FilterNameDialog(QWidget *parent) + : QDialog(parent) +{ + m_ui.setupUi(this); + connect(m_ui.buttonBox->button(QDialogButtonBox::Ok), + SIGNAL(clicked()), this, SLOT(accept())); + connect(m_ui.buttonBox->button(QDialogButtonBox::Cancel), + SIGNAL(clicked()), this, SLOT(reject())); + connect(m_ui.lineEdit, SIGNAL(textChanged(QString)), + this, SLOT(updateOkButton())); + m_ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(true); + +} + +QString FilterNameDialog::filterName() const +{ + return m_ui.lineEdit->text(); +} + +void FilterNameDialog::updateOkButton() +{ + m_ui.buttonBox->button(QDialogButtonBox::Ok) + ->setDisabled(m_ui.lineEdit->text().isEmpty()); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/filternamedialog.h b/tools/assistant/tools/assistant/filternamedialog.h new file mode 100644 index 0000000..32e849c --- /dev/null +++ b/tools/assistant/tools/assistant/filternamedialog.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FILTERNAMEDIALOG_H +#define FILTERNAMEDIALOG_H + +#include <QtGui/QDialog> +#include "ui_filternamedialog.h" + +QT_BEGIN_NAMESPACE + +class FilterNameDialog : public QDialog +{ + Q_OBJECT + +public: + FilterNameDialog(QWidget *parent = 0); + QString filterName() const; + +private slots: + void updateOkButton(); + +private: + Ui::FilterNameDialogClass m_ui; +}; + +QT_END_NAMESPACE + +#endif // FILTERNAMEDIALOG_H diff --git a/tools/assistant/tools/assistant/filternamedialog.ui b/tools/assistant/tools/assistant/filternamedialog.ui new file mode 100644 index 0000000..755a934 --- /dev/null +++ b/tools/assistant/tools/assistant/filternamedialog.ui @@ -0,0 +1,67 @@ +<ui version="4.0" > + <class>FilterNameDialogClass</class> + <widget class="QDialog" name="FilterNameDialogClass" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>312</width> + <height>95</height> + </rect> + </property> + <property name="windowTitle" > + <string>Add Filter Name</string> + </property> + <layout class="QGridLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item row="0" column="0" > + <widget class="QLabel" name="label" > + <property name="text" > + <string>Filter Name:</string> + </property> + </widget> + </item> + <item row="0" column="1" colspan="2" > + <widget class="QLineEdit" name="lineEdit" /> + </item> + <item row="1" column="0" colspan="3" > + <widget class="Line" name="line" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="2" column="0" colspan="2" > + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="2" > + <widget class="QDialogButtonBox" name="buttonBox" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons" > + <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <layoutdefault spacing="6" margin="11" /> + <resources/> + <connections/> +</ui> diff --git a/tools/assistant/tools/assistant/helpviewer.cpp b/tools/assistant/tools/assistant/helpviewer.cpp new file mode 100644 index 0000000..9817f23 --- /dev/null +++ b/tools/assistant/tools/assistant/helpviewer.cpp @@ -0,0 +1,556 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "helpviewer.h" +#include "centralwidget.h" + +#include <QtCore/QDir> +#include <QtCore/QEvent> +#include <QtCore/QVariant> +#include <QtCore/QByteArray> +#include <QtCore/QTimer> + +#include <QtGui/QMenu> +#include <QtGui/QKeyEvent> +#include <QtGui/QClipboard> +#include <QtGui/QApplication> +#include <QtGui/QMessageBox> +#include <QtGui/QDesktopServices> + +#include <QtHelp/QHelpEngine> + +#include <QNetworkAccessManager> +#include <QNetworkReply> +#include <QNetworkRequest> + +QT_BEGIN_NAMESPACE + +#if !defined(QT_NO_WEBKIT) + +class HelpNetworkReply : public QNetworkReply +{ +public: + HelpNetworkReply(const QNetworkRequest &request, const QByteArray &fileData, + const QString &mimeType); + + virtual void abort(); + + virtual qint64 bytesAvailable() const + { return data.length() + QNetworkReply::bytesAvailable(); } + +protected: + virtual qint64 readData(char *data, qint64 maxlen); + +private: + QByteArray data; + qint64 origLen; +}; + +HelpNetworkReply::HelpNetworkReply(const QNetworkRequest &request, + const QByteArray &fileData, const QString& mimeType) + : data(fileData), origLen(fileData.length()) +{ + setRequest(request); + setOpenMode(QIODevice::ReadOnly); + + setHeader(QNetworkRequest::ContentTypeHeader, mimeType); + setHeader(QNetworkRequest::ContentLengthHeader, QByteArray::number(origLen)); + QTimer::singleShot(0, this, SIGNAL(metaDataChanged())); + QTimer::singleShot(0, this, SIGNAL(readyRead())); +} + +void HelpNetworkReply::abort() +{ + // nothing to do +} + +qint64 HelpNetworkReply::readData(char *buffer, qint64 maxlen) +{ + qint64 len = qMin(qint64(data.length()), maxlen); + if (len) { + qMemCopy(buffer, data.constData(), len); + data.remove(0, len); + } + if (!data.length()) + QTimer::singleShot(0, this, SIGNAL(finished())); + return len; +} + +class HelpNetworkAccessManager : public QNetworkAccessManager +{ +public: + HelpNetworkAccessManager(QHelpEngine *engine, QObject *parent); + +protected: + virtual QNetworkReply *createRequest(Operation op, + const QNetworkRequest &request, QIODevice *outgoingData = 0); + +private: + QHelpEngine *helpEngine; +}; + +HelpNetworkAccessManager::HelpNetworkAccessManager(QHelpEngine *engine, + QObject *parent) + : QNetworkAccessManager(parent), helpEngine(engine) +{ +} + +QNetworkReply *HelpNetworkAccessManager::createRequest(Operation op, + const QNetworkRequest &request, QIODevice *outgoingData) +{ + const QString& scheme = request.url().scheme(); + if (scheme == QLatin1String("qthelp") || scheme == QLatin1String("about")) { + 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 { + mimeType = QLatin1String("text/html"); + } + return new HelpNetworkReply(request, helpEngine->fileData(url), mimeType); + } + return QNetworkAccessManager::createRequest(op, request, outgoingData); +} + +class HelpPage : public QWebPage +{ +public: + HelpPage(CentralWidget *central, QHelpEngine *engine, QObject *parent); + +protected: + virtual QWebPage *createWindow(QWebPage::WebWindowType); + + virtual bool acceptNavigationRequest(QWebFrame *frame, + const QNetworkRequest &request, NavigationType type); + +private: + CentralWidget *centralWidget; + QHelpEngine *helpEngine; +}; + +HelpPage::HelpPage(CentralWidget *central, QHelpEngine *engine, QObject *parent) + : QWebPage(parent), centralWidget(central), helpEngine(engine) +{ +} + +QWebPage *HelpPage::createWindow(QWebPage::WebWindowType) +{ + return centralWidget->newEmptyTab()->page(); +} + +static bool isLocalUrl(const QUrl &url) +{ + const QString scheme = url.scheme(); + if (scheme.isEmpty() + || scheme == QLatin1String("file") + || scheme == QLatin1String("qrc") + || scheme == QLatin1String("data") + || scheme == QLatin1String("qthelp") + || scheme == QLatin1String("about")) + return true; + return false; +} + +bool HelpPage::acceptNavigationRequest(QWebFrame *, + const QNetworkRequest &request, QWebPage::NavigationType) +{ + const QUrl &url = request.url(); + if (isLocalUrl(url)) { + if (url.path().endsWith(QLatin1String("pdf"))) { + QString fileName = url.toString(); + fileName = QDir::tempPath() + QDir::separator() + fileName.right + (fileName.length() - fileName.lastIndexOf(QChar('/'))); + + QFile tmpFile(QDir::cleanPath(fileName)); + if (tmpFile.open(QIODevice::ReadWrite)) { + tmpFile.write(helpEngine->fileData(url)); + tmpFile.close(); + } + QDesktopServices::openUrl(QUrl(tmpFile.fileName())); + return false; + } + return true; + } + + QDesktopServices::openUrl(url); + return false; +} + +HelpViewer::HelpViewer(QHelpEngine *engine, CentralWidget *parent) + : QWebView(parent), helpEngine(engine), parentWidget(parent) +{ + 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))); +} + +void HelpViewer::setSource(const QUrl &url) +{ + 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()); +} + +#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")) { + QString fileName = url.toString(); + fileName = QDir::tempPath() + QDir::separator() + fileName.right + (fileName.length() - fileName.lastIndexOf(QLatin1Char('/'))); + + 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); + } + + if (!launched) { + QMessageBox::information(this, tr("Help"), + tr("Unable to launch external application.\n"), tr("OK")); + } + return true; + } + 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 new file mode 100644 index 0000000..af5c197 --- /dev/null +++ b/tools/assistant/tools/assistant/helpviewer.h @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef HELPVIEWER_H +#define HELPVIEWER_H + +#include <QtCore/QUrl> +#include <QtCore/QVariant> +#include <QtGui/QTextBrowser> +#include <QtGui/QAction> + +#if !defined(QT_NO_WEBKIT) +#include <QWebView> +#endif + +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(); } + +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); + +private Q_SLOTS: + void actionChanged(); + +private: + QHelpEngine *helpEngine; + CentralWidget* parentWidget; +}; + +#else + +class HelpViewer : public QTextBrowser +{ + Q_OBJECT + +public: + HelpViewer(QHelpEngine *helpEngine, CentralWidget *parent); + void setSource(const QUrl &url); + + void resetZoom(); + void zoomIn(int range = 1); + void zoomOut(int range = 1); + int zoom() const { return zoomCount; } + void setZoom(int zoom) { zoomCount = zoom; } + + inline bool hasSelection() const + { return textCursor().hasSelection(); } + + bool launchedWithExternalApp(const QUrl &url); + +public Q_SLOTS: + void home(); + +protected: + void wheelEvent(QWheelEvent *e); + +private: + QVariant loadResource(int type, const QUrl &name); + void openLinkInNewTab(const QString &link); + bool hasAnchorAt(const QPoint& pos); + void contextMenuEvent(QContextMenuEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + void keyPressEvent(QKeyEvent *e); + +private slots: + void openLinkInNewTab(); + +private: + int zoomCount; + bool controlPressed; + QString lastAnchor; + QHelpEngine *helpEngine; + CentralWidget* parentWidget; +}; + +#endif + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/tools/assistant/images/assistant-128.png b/tools/assistant/tools/assistant/images/assistant-128.png Binary files differnew file mode 100644 index 0000000..f05949f --- /dev/null +++ b/tools/assistant/tools/assistant/images/assistant-128.png diff --git a/tools/assistant/tools/assistant/images/assistant.png b/tools/assistant/tools/assistant/images/assistant.png Binary files differnew file mode 100644 index 0000000..ea4d1e7 --- /dev/null +++ b/tools/assistant/tools/assistant/images/assistant.png diff --git a/tools/assistant/tools/assistant/images/mac/addtab.png b/tools/assistant/tools/assistant/images/mac/addtab.png Binary files differnew file mode 100644 index 0000000..20928fb --- /dev/null +++ b/tools/assistant/tools/assistant/images/mac/addtab.png diff --git a/tools/assistant/tools/assistant/images/mac/book.png b/tools/assistant/tools/assistant/images/mac/book.png Binary files differnew file mode 100644 index 0000000..7a3204c --- /dev/null +++ b/tools/assistant/tools/assistant/images/mac/book.png diff --git a/tools/assistant/tools/assistant/images/mac/closetab.png b/tools/assistant/tools/assistant/images/mac/closetab.png Binary files differnew file mode 100644 index 0000000..ab9d669 --- /dev/null +++ b/tools/assistant/tools/assistant/images/mac/closetab.png diff --git a/tools/assistant/tools/assistant/images/mac/editcopy.png b/tools/assistant/tools/assistant/images/mac/editcopy.png Binary files differnew file mode 100644 index 0000000..f551364 --- /dev/null +++ b/tools/assistant/tools/assistant/images/mac/editcopy.png diff --git a/tools/assistant/tools/assistant/images/mac/find.png b/tools/assistant/tools/assistant/images/mac/find.png Binary files differnew file mode 100644 index 0000000..3561745 --- /dev/null +++ b/tools/assistant/tools/assistant/images/mac/find.png diff --git a/tools/assistant/tools/assistant/images/mac/home.png b/tools/assistant/tools/assistant/images/mac/home.png Binary files differnew file mode 100644 index 0000000..78d94da --- /dev/null +++ b/tools/assistant/tools/assistant/images/mac/home.png diff --git a/tools/assistant/tools/assistant/images/mac/next.png b/tools/assistant/tools/assistant/images/mac/next.png Binary files differnew file mode 100644 index 0000000..a585cab --- /dev/null +++ b/tools/assistant/tools/assistant/images/mac/next.png diff --git a/tools/assistant/tools/assistant/images/mac/previous.png b/tools/assistant/tools/assistant/images/mac/previous.png Binary files differnew file mode 100644 index 0000000..612fb34 --- /dev/null +++ b/tools/assistant/tools/assistant/images/mac/previous.png diff --git a/tools/assistant/tools/assistant/images/mac/print.png b/tools/assistant/tools/assistant/images/mac/print.png Binary files differnew file mode 100644 index 0000000..10ca56c --- /dev/null +++ b/tools/assistant/tools/assistant/images/mac/print.png diff --git a/tools/assistant/tools/assistant/images/mac/resetzoom.png b/tools/assistant/tools/assistant/images/mac/resetzoom.png Binary files differnew file mode 100644 index 0000000..759b382 --- /dev/null +++ b/tools/assistant/tools/assistant/images/mac/resetzoom.png diff --git a/tools/assistant/tools/assistant/images/mac/synctoc.png b/tools/assistant/tools/assistant/images/mac/synctoc.png Binary files differnew file mode 100644 index 0000000..067fa94 --- /dev/null +++ b/tools/assistant/tools/assistant/images/mac/synctoc.png diff --git a/tools/assistant/tools/assistant/images/mac/zoomin.png b/tools/assistant/tools/assistant/images/mac/zoomin.png Binary files differnew file mode 100644 index 0000000..d46f5af --- /dev/null +++ b/tools/assistant/tools/assistant/images/mac/zoomin.png diff --git a/tools/assistant/tools/assistant/images/mac/zoomout.png b/tools/assistant/tools/assistant/images/mac/zoomout.png Binary files differnew file mode 100644 index 0000000..4632656 --- /dev/null +++ b/tools/assistant/tools/assistant/images/mac/zoomout.png diff --git a/tools/assistant/tools/assistant/images/trolltech-logo.png b/tools/assistant/tools/assistant/images/trolltech-logo.png Binary files differnew file mode 100644 index 0000000..c53e744 --- /dev/null +++ b/tools/assistant/tools/assistant/images/trolltech-logo.png diff --git a/tools/assistant/tools/assistant/images/win/addtab.png b/tools/assistant/tools/assistant/images/win/addtab.png Binary files differnew file mode 100644 index 0000000..4bb0feb --- /dev/null +++ b/tools/assistant/tools/assistant/images/win/addtab.png diff --git a/tools/assistant/tools/assistant/images/win/book.png b/tools/assistant/tools/assistant/images/win/book.png Binary files differnew file mode 100644 index 0000000..09ec4d3 --- /dev/null +++ b/tools/assistant/tools/assistant/images/win/book.png diff --git a/tools/assistant/tools/assistant/images/win/closetab.png b/tools/assistant/tools/assistant/images/win/closetab.png Binary files differnew file mode 100644 index 0000000..ef9e020 --- /dev/null +++ b/tools/assistant/tools/assistant/images/win/closetab.png diff --git a/tools/assistant/tools/assistant/images/win/editcopy.png b/tools/assistant/tools/assistant/images/win/editcopy.png Binary files differnew file mode 100644 index 0000000..1121b47 --- /dev/null +++ b/tools/assistant/tools/assistant/images/win/editcopy.png diff --git a/tools/assistant/tools/assistant/images/win/find.png b/tools/assistant/tools/assistant/images/win/find.png Binary files differnew file mode 100644 index 0000000..6ea35e9 --- /dev/null +++ b/tools/assistant/tools/assistant/images/win/find.png diff --git a/tools/assistant/tools/assistant/images/win/home.png b/tools/assistant/tools/assistant/images/win/home.png Binary files differnew file mode 100644 index 0000000..b1c6ae1 --- /dev/null +++ b/tools/assistant/tools/assistant/images/win/home.png diff --git a/tools/assistant/tools/assistant/images/win/next.png b/tools/assistant/tools/assistant/images/win/next.png Binary files differnew file mode 100644 index 0000000..8df4127 --- /dev/null +++ b/tools/assistant/tools/assistant/images/win/next.png diff --git a/tools/assistant/tools/assistant/images/win/previous.png b/tools/assistant/tools/assistant/images/win/previous.png Binary files differnew file mode 100644 index 0000000..0780bc2 --- /dev/null +++ b/tools/assistant/tools/assistant/images/win/previous.png diff --git a/tools/assistant/tools/assistant/images/win/print.png b/tools/assistant/tools/assistant/images/win/print.png Binary files differnew file mode 100644 index 0000000..ba7c02d --- /dev/null +++ b/tools/assistant/tools/assistant/images/win/print.png diff --git a/tools/assistant/tools/assistant/images/win/resetzoom.png b/tools/assistant/tools/assistant/images/win/resetzoom.png Binary files differnew file mode 100644 index 0000000..b69ae4e --- /dev/null +++ b/tools/assistant/tools/assistant/images/win/resetzoom.png diff --git a/tools/assistant/tools/assistant/images/win/synctoc.png b/tools/assistant/tools/assistant/images/win/synctoc.png Binary files differnew file mode 100644 index 0000000..da301bc --- /dev/null +++ b/tools/assistant/tools/assistant/images/win/synctoc.png diff --git a/tools/assistant/tools/assistant/images/win/zoomin.png b/tools/assistant/tools/assistant/images/win/zoomin.png Binary files differnew file mode 100644 index 0000000..2e586fc --- /dev/null +++ b/tools/assistant/tools/assistant/images/win/zoomin.png diff --git a/tools/assistant/tools/assistant/images/win/zoomout.png b/tools/assistant/tools/assistant/images/win/zoomout.png Binary files differnew file mode 100644 index 0000000..a736d39 --- /dev/null +++ b/tools/assistant/tools/assistant/images/win/zoomout.png diff --git a/tools/assistant/tools/assistant/images/wrap.png b/tools/assistant/tools/assistant/images/wrap.png Binary files differnew file mode 100644 index 0000000..90f18d9 --- /dev/null +++ b/tools/assistant/tools/assistant/images/wrap.png diff --git a/tools/assistant/tools/assistant/indexwindow.cpp b/tools/assistant/tools/assistant/indexwindow.cpp new file mode 100644 index 0000000..e7575fa --- /dev/null +++ b/tools/assistant/tools/assistant/indexwindow.cpp @@ -0,0 +1,216 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "indexwindow.h" +#include "centralwidget.h" +#include "topicchooser.h" + +#include <QtGui/QLayout> +#include <QtGui/QLabel> +#include <QtGui/QLineEdit> +#include <QtGui/QKeyEvent> +#include <QtGui/QMenu> +#include <QtGui/QContextMenuEvent> +#include <QtGui/QListWidgetItem> + +#include <QtHelp/QHelpEngine> +#include <QtHelp/QHelpIndexWidget> + +QT_BEGIN_NAMESPACE + +IndexWindow::IndexWindow(QHelpEngine *helpEngine, QWidget *parent) + : QWidget(parent) + , m_searchLineEdit(0) + , m_indexWidget(0) + , m_helpEngine(helpEngine) +{ + 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))); + m_searchLineEdit->installEventFilter(this); + layout->setMargin(4); + layout->addWidget(m_searchLineEdit); + + m_indexWidget = m_helpEngine->indexWidget(); + m_indexWidget->installEventFilter(this); + connect(m_helpEngine->indexModel(), SIGNAL(indexCreationStarted()), this, + SLOT(disableSearchLineEdit())); + connect(m_helpEngine->indexModel(), SIGNAL(indexCreated()), this, + SLOT(enableSearchLineEdit())); + connect(m_indexWidget, SIGNAL(linkActivated(QUrl, QString)), this, + SIGNAL(linkActivated(QUrl))); + connect(m_indexWidget, SIGNAL(linksActivated(QMap<QString, QUrl>, QString)), + this, SIGNAL(linksActivated(QMap<QString, QUrl>, QString))); + connect(m_searchLineEdit, SIGNAL(returnPressed()), m_indexWidget, + SLOT(activateCurrentItem())); + layout->addWidget(m_indexWidget); + + m_indexWidget->viewport()->installEventFilter(this); +} + +IndexWindow::~IndexWindow() +{ +} + +void IndexWindow::filterIndices(const QString &filter) +{ + if (filter.contains(QLatin1Char('*'))) + m_indexWidget->filterIndices(filter, filter); + else + m_indexWidget->filterIndices(filter, QString()); +} + +bool IndexWindow::eventFilter(QObject *obj, QEvent *e) +{ + if (obj == m_searchLineEdit && e->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast<QKeyEvent*>(e); + QModelIndex idx = m_indexWidget->currentIndex(); + switch (ke->key()) { + case Qt::Key_Up: + idx = m_indexWidget->model()->index(idx.row()-1, + idx.column(), idx.parent()); + if (idx.isValid()) + m_indexWidget->setCurrentIndex(idx); + break; + case Qt::Key_Down: + idx = m_indexWidget->model()->index(idx.row()+1, + idx.column(), idx.parent()); + if (idx.isValid()) + m_indexWidget->setCurrentIndex(idx); + break; + case Qt::Key_Escape: + emit escapePressed(); + break; + default: + ; + } + } else if (obj == m_indexWidget && e->type() == QEvent::ContextMenu) { + QContextMenuEvent *ctxtEvent = static_cast<QContextMenuEvent*>(e); + QModelIndex idx = m_indexWidget->indexAt(ctxtEvent->pos()); + if (idx.isValid()) { + QMenu menu; + QAction *curTab = menu.addAction(tr("Open Link")); + QAction *newTab = menu.addAction(tr("Open Link in New Tab")); + menu.move(m_indexWidget->mapToGlobal(ctxtEvent->pos())); + + QAction *action = menu.exec(); + if (curTab == action) + m_indexWidget->activateCurrentItem(); + else if (newTab == action) { + QHelpIndexModel *model = + qobject_cast<QHelpIndexModel*>(m_indexWidget->model()); + QString keyword = model->data(idx, Qt::DisplayRole).toString(); + if (model) { + QMap<QString, QUrl> links = model->linksForKeyword(keyword); + if (links.count() == 1) { + CentralWidget::instance()-> + setSourceInNewTab(links.constBegin().value()); + } else { + TopicChooser tc(this, keyword, links); + if (tc.exec() == QDialog::Accepted) { + CentralWidget::instance()->setSourceInNewTab(tc.link()); + } + } + } + } + } + } else if (m_indexWidget && obj == m_indexWidget->viewport() + && e->type() == QEvent::MouseButtonRelease) { + QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(e); + QModelIndex idx = m_indexWidget->indexAt(mouseEvent->pos()); + if (idx.isValid() && mouseEvent->button()==Qt::MidButton) { + QHelpIndexModel *model = + qobject_cast<QHelpIndexModel*>(m_indexWidget->model()); + QString keyword = model->data(idx, Qt::DisplayRole).toString(); + if (model) { + QMap<QString, QUrl> links = model->linksForKeyword(keyword); + if (links.count() > 1) { + TopicChooser tc(this, keyword, links); + if (tc.exec() == QDialog::Accepted) { + CentralWidget::instance()->setSourceInNewTab(tc.link()); + } + } else if (links.count() == 1) { + CentralWidget::instance()-> + setSourceInNewTab(links.constBegin().value()); + } + } + } + } +#ifdef Q_OS_MAC + else if (obj == m_indexWidget && e->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast<QKeyEvent*>(e); + if (ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter) + m_indexWidget->activateCurrentItem(); + } +#endif + return QWidget::eventFilter(obj, e); +} + +void IndexWindow::enableSearchLineEdit() +{ + m_searchLineEdit->setDisabled(false); + filterIndices(m_searchLineEdit->text()); +} + +void IndexWindow::disableSearchLineEdit() +{ + m_searchLineEdit->setDisabled(true); +} + +void IndexWindow::setSearchLineEditText(const QString &text) +{ + m_searchLineEdit->setText(text); +} + +void IndexWindow::focusInEvent(QFocusEvent *e) +{ + if (e->reason() != Qt::MouseFocusReason) { + m_searchLineEdit->selectAll(); + m_searchLineEdit->setFocus(); + } +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/indexwindow.h b/tools/assistant/tools/assistant/indexwindow.h new file mode 100644 index 0000000..f1f57f9 --- /dev/null +++ b/tools/assistant/tools/assistant/indexwindow.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef INDEXWINDOW_H +#define INDEXWINDOW_H + +#include <QtCore/QUrl> +#include <QtGui/QWidget> +#include <QtGui/QLineEdit> + +QT_BEGIN_NAMESPACE + +class QHelpIndexWidget; +class QHelpEngine; + +class IndexWindow : public QWidget +{ + Q_OBJECT + +public: + IndexWindow(QHelpEngine *helpEngine, QWidget *parent = 0); + ~IndexWindow(); + + void setSearchLineEditText(const QString &text); + QString searchLineEditText() const + { + return m_searchLineEdit->text(); + } + +signals: + void linkActivated(const QUrl &link); + void linksActivated(const QMap<QString, QUrl> &links, + const QString &keyword); + void escapePressed(); + +private slots: + void filterIndices(const QString &filter); + void enableSearchLineEdit(); + void disableSearchLineEdit(); + +private: + bool eventFilter(QObject *obj, QEvent *e); + void focusInEvent(QFocusEvent *e); + + QLineEdit *m_searchLineEdit; + QHelpIndexWidget *m_indexWidget; + QHelpEngine *m_helpEngine; +}; + +QT_END_NAMESPACE + +#endif // INDEXWINDOW_H diff --git a/tools/assistant/tools/assistant/installdialog.cpp b/tools/assistant/tools/assistant/installdialog.cpp new file mode 100644 index 0000000..1f02ac1 --- /dev/null +++ b/tools/assistant/tools/assistant/installdialog.cpp @@ -0,0 +1,338 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "installdialog.h" + +#include <QtCore/QTimer> +#include <QtCore/QUrl> +#include <QtCore/QBuffer> +#include <QtCore/QDir> +#include <QtCore/QFile> +#include <QtCore/QCryptographicHash> + +#include <QtGui/QMessageBox> +#include <QtGui/QFileDialog> + +#include <QtHelp/QHelpEngineCore> + +#include <QtNetwork/QHttp> + +QT_BEGIN_NAMESPACE + +#define QCH_FILENAME 92943 +#define QCH_NAMESPACE 92944 +#define QCH_CHECKSUM 92945 + +InstallDialog::InstallDialog(QHelpEngineCore *helpEngine, QWidget *parent, + const QString &host, int port) + : QDialog(parent), m_helpEngine(helpEngine), m_host(host), m_port(port) +{ + m_ui.setupUi(this); + + m_ui.installButton->setEnabled(false); + m_ui.cancelButton->setEnabled(false); + m_ui.pathLineEdit->setText(QFileInfo(m_helpEngine->collectionFile()).absolutePath()); + m_ui.progressBar->hide(); + + m_windowTitle = tr("Install Documentation"); + + m_http = new QHttp(this); + connect(m_http, SIGNAL(requestFinished(int, bool)), + this, SLOT(httpRequestFinished(int, bool))); + connect(m_http, SIGNAL(dataReadProgress(int, int)), + this, SLOT(updateDataReadProgress(int, int))); + connect(m_http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)), + this, SLOT(readResponseHeader(const QHttpResponseHeader &))); + connect(m_ui.installButton, SIGNAL(clicked()), this, SLOT(install())); + connect(m_ui.cancelButton, SIGNAL(clicked()), this, SLOT(cancelDownload())); + connect(m_ui.browseButton, SIGNAL(clicked()), this, SLOT(browseDirectories())); + + connect(m_ui.listWidget, SIGNAL(itemChanged(QListWidgetItem*)), + this, SLOT(updateInstallButton())); + + QTimer::singleShot(0, this, SLOT(init())); +} + +InstallDialog::~InstallDialog() +{ +} + +QStringList InstallDialog::installedDocumentations() const +{ + return m_installedDocumentations; +} + +void InstallDialog::init() +{ + m_ui.statusLabel->setText(tr("Downloading documentation info...")); + m_ui.progressBar->show(); + + QUrl url(QLatin1String("http://doc.trolltech.com/assistantdocs/docs.txt")); + m_buffer = new QBuffer(); + m_buffer->open(QBuffer::ReadWrite); + + if (m_port > -1) + m_http->setProxy(m_host, m_port); + m_http->setHost(url.host()); + m_httpAborted = false; + m_docInfoId = m_http->get(url.path(), m_buffer); + + m_ui.cancelButton->setEnabled(true); + m_ui.closeButton->setEnabled(false); +} + +void InstallDialog::updateInstallButton() +{ + QListWidgetItem *item = 0; + for (int i=0; i<m_ui.listWidget->count(); ++i) { + item = m_ui.listWidget->item(i); + if (item->checkState() == Qt::Checked + && item->flags() & Qt::ItemIsEnabled) { + m_ui.installButton->setEnabled(true); + return; + } + } + m_ui.installButton->setEnabled(false); +} + +void InstallDialog::updateDocItemList() +{ + QStringList registeredDocs = m_helpEngine->registeredDocumentations(); + QListWidgetItem *item = 0; + for (int i=0; i<m_ui.listWidget->count(); ++i) { + item = m_ui.listWidget->item(i); + QString ns = item->data(QCH_NAMESPACE).toString(); + if (!ns.isEmpty() && registeredDocs.contains(ns)) { + item->setFlags(Qt::ItemIsUserCheckable); + item->setCheckState(Qt::Checked); + } + item->setCheckState(Qt::Unchecked); + } +} + +void InstallDialog::cancelDownload() +{ + m_ui.statusLabel->setText(tr("Download canceled.")); + m_httpAborted = true; + m_itemsToInstall.clear(); + m_http->abort(); + m_ui.cancelButton->setEnabled(false); + m_ui.closeButton->setEnabled(true); + updateInstallButton(); +} + +void InstallDialog::install() +{ + QListWidgetItem *item = 0; + for (int i=0; i<m_ui.listWidget->count(); ++i) { + item = m_ui.listWidget->item(i); + if (item->checkState() == Qt::Checked) + m_itemsToInstall.append(item); + } + m_ui.installButton->setEnabled(false); + downloadNextFile(); +} + +void InstallDialog::downloadNextFile() +{ + if (!m_itemsToInstall.count()) { + m_ui.cancelButton->setEnabled(false); + m_ui.closeButton->setEnabled(true); + m_ui.statusLabel->setText(tr("Done.")); + m_ui.progressBar->hide(); + updateDocItemList(); + updateInstallButton(); + return; + } + + QListWidgetItem *item = m_itemsToInstall.dequeue(); + m_currentCheckSum = item->data(QCH_CHECKSUM).toString(); + QString fileName = item->data(QCH_FILENAME).toString(); + QString saveFileName = m_ui.pathLineEdit->text() + QDir::separator() + + fileName; + + if (QFile::exists(saveFileName) + && QMessageBox::information(this, m_windowTitle, + tr("The file %1 already exists. Do you want to overwrite it?") + .arg(saveFileName), QMessageBox::Yes | QMessageBox::No, + QMessageBox::Yes) == QMessageBox::No) { + installFile(saveFileName); + downloadNextFile(); + return; + } + + m_file = new QFile(saveFileName); + if (!m_file->open(QIODevice::WriteOnly|QIODevice::Truncate)) { + QMessageBox::information(this, m_windowTitle, + tr("Unable to save the file %1: %2.") + .arg(saveFileName).arg(m_file->errorString())); + delete m_file; + m_file = 0; + downloadNextFile(); + return; + } + + m_ui.statusLabel->setText(tr("Downloading %1...").arg(fileName)); + m_ui.progressBar->show(); + + QLatin1String urlStr("http://doc.trolltech.com/assistantdocs/%1"); + QUrl url(QString(urlStr).arg(fileName)); + + m_httpAborted = false; + m_docId = m_http->get(url.path(), m_file); + + m_ui.cancelButton->setEnabled(true); + m_ui.closeButton->setEnabled(false); +} + +void InstallDialog::httpRequestFinished(int requestId, bool error) +{ + if (requestId == m_docInfoId && m_buffer) { + m_ui.progressBar->hide(); + if (error) { + QMessageBox::information(this, m_windowTitle, + tr("Download failed: %1.") + .arg(m_http->errorString())); + } else if (!m_httpAborted) { + QStringList registeredDocs = m_helpEngine->registeredDocumentations(); + m_buffer->seek(0); + while (m_buffer->canReadLine()) { + QByteArray ba = m_buffer->readLine(); + QStringList lst = QString::fromAscii(ba.constData()).split(QLatin1Char('|')); + if (lst.count() != 4) { + QMessageBox::information(this, m_windowTitle, + tr("Documentation info file is corrupt!")); + } else { + QListWidgetItem *item = new QListWidgetItem(m_ui.listWidget); + item->setText(lst.at(2).trimmed()); + item->setData(QCH_FILENAME, lst.first()); + item->setData(QCH_NAMESPACE, lst.at(1)); + item->setData(QCH_CHECKSUM, lst.last().trimmed()); + } + } + updateDocItemList(); + } + if (m_buffer) + m_buffer->close(); + delete m_buffer; + m_buffer = 0; + m_ui.statusLabel->setText(tr("Done.")); + m_ui.cancelButton->setEnabled(false); + m_ui.closeButton->setEnabled(true); + updateInstallButton(); + } else if (requestId == m_docId) { + m_file->close(); + if (!m_httpAborted) { + QString checkSum; + if (m_file->open(QIODevice::ReadOnly)) { + QByteArray digest = QCryptographicHash::hash(m_file->readAll(), + QCryptographicHash::Md5); + m_file->close(); + checkSum = QString::fromLatin1(digest.toHex()); + } + if (error) { + m_file->remove(); + QMessageBox::warning(this, m_windowTitle, + tr("Download failed: %1.") + .arg(m_http->errorString())); + } else if (checkSum.isEmpty() || m_currentCheckSum != checkSum) { + m_file->remove(); + QMessageBox::warning(this, m_windowTitle, + tr("Download failed: Downloaded file is corrupted.")); + } else { + m_ui.statusLabel->setText(tr("Installing documentation %1...") + .arg(QFileInfo(m_file->fileName()).fileName())); + m_ui.progressBar->setMaximum(0); + m_ui.statusLabel->setText(tr("Done.")); + installFile(m_file->fileName()); + } + } else { + m_file->remove(); + } + delete m_file; + m_file = 0; + downloadNextFile(); + } +} + +void InstallDialog::installFile(const QString &fileName) +{ + if (m_helpEngine->registerDocumentation(fileName)) { + m_installedDocumentations + .append(QHelpEngineCore::namespaceName(fileName)); + } else { + QMessageBox::information(this, m_windowTitle, + tr("Error while installing documentation:\n%1") + .arg(m_helpEngine->error())); + } +} + +void InstallDialog::readResponseHeader(const QHttpResponseHeader &responseHeader) +{ + if (responseHeader.statusCode() != 200) { + QMessageBox::information(this, m_windowTitle, + tr("Download failed: %1.") + .arg(responseHeader.reasonPhrase())); + m_httpAborted = true; + m_ui.progressBar->hide(); + m_http->abort(); + return; + } +} + +void InstallDialog::updateDataReadProgress(int bytesRead, int totalBytes) +{ + if (m_httpAborted) + return; + + m_ui.progressBar->setMaximum(totalBytes); + m_ui.progressBar->setValue(bytesRead); +} + +void InstallDialog::browseDirectories() +{ + QString dir = QFileDialog::getExistingDirectory(this, m_windowTitle, + m_ui.pathLineEdit->text()); + if (!dir.isEmpty()) + m_ui.pathLineEdit->setText(dir); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/installdialog.h b/tools/assistant/tools/assistant/installdialog.h new file mode 100644 index 0000000..88c882c --- /dev/null +++ b/tools/assistant/tools/assistant/installdialog.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef INSTALLDIALOG_H +#define INSTALLDIALOG_H + +#include <QtCore/QQueue> +#include <QtGui/QDialog> +#include <QtNetwork/QHttpResponseHeader> +#include "ui_installdialog.h" + +QT_BEGIN_NAMESPACE + +class QHttp; +class QBuffer; +class QFile; +class QHelpEngineCore; + +class InstallDialog : public QDialog +{ + Q_OBJECT + +public: + InstallDialog(QHelpEngineCore *helpEngine, QWidget *parent = 0, + const QString &host = QString(), int port = -1); + ~InstallDialog(); + + QStringList installedDocumentations() const; + +private slots: + void init(); + void cancelDownload(); + void install(); + void httpRequestFinished(int requestId, bool error); + void readResponseHeader(const QHttpResponseHeader &responseHeader); + void updateDataReadProgress(int bytesRead, int totalBytes); + void updateInstallButton(); + void browseDirectories(); + +private: + void downloadNextFile(); + void updateDocItemList(); + void installFile(const QString &fileName); + + Ui::InstallDialog m_ui; + QHelpEngineCore *m_helpEngine; + QHttp *m_http; + QBuffer *m_buffer; + QFile *m_file; + bool m_httpAborted; + int m_docInfoId; + int m_docId; + QQueue<QListWidgetItem*> m_itemsToInstall; + QString m_currentCheckSum; + QString m_windowTitle; + QStringList m_installedDocumentations; + QString m_host; + int m_port; +}; + +QT_END_NAMESPACE + +#endif // INSTALLDIALOG_H diff --git a/tools/assistant/tools/assistant/installdialog.ui b/tools/assistant/tools/assistant/installdialog.ui new file mode 100644 index 0000000..21a05da --- /dev/null +++ b/tools/assistant/tools/assistant/installdialog.ui @@ -0,0 +1,118 @@ +<ui version="4.0" > + <class>InstallDialog</class> + <widget class="QDialog" name="InstallDialog" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>436</width> + <height>245</height> + </rect> + </property> + <property name="windowTitle" > + <string>Install Documentation</string> + </property> + <layout class="QGridLayout" > + <item row="0" column="0" colspan="4" > + <widget class="QLabel" name="label" > + <property name="text" > + <string>Available Documentation:</string> + </property> + </widget> + </item> + <item rowspan="4" row="1" column="0" colspan="4" > + <widget class="QListWidget" name="listWidget" /> + </item> + <item row="1" column="4" > + <widget class="QPushButton" name="installButton" > + <property name="text" > + <string>Install</string> + </property> + </widget> + </item> + <item row="2" column="4" > + <widget class="QPushButton" name="cancelButton" > + <property name="text" > + <string>Cancel</string> + </property> + </widget> + </item> + <item row="3" column="4" > + <widget class="QPushButton" name="closeButton" > + <property name="text" > + <string>Close</string> + </property> + </widget> + </item> + <item row="4" column="4" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>56</height> + </size> + </property> + </spacer> + </item> + <item row="5" column="0" > + <widget class="QLabel" name="label_4" > + <property name="text" > + <string>Installation Path:</string> + </property> + </widget> + </item> + <item row="5" column="1" colspan="2" > + <widget class="QLineEdit" name="pathLineEdit" /> + </item> + <item row="5" column="3" > + <widget class="QToolButton" name="browseButton" > + <property name="text" > + <string>...</string> + </property> + </widget> + </item> + <item row="6" column="0" colspan="5" > + <widget class="Line" name="line" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="7" column="0" colspan="2" > + <widget class="QLabel" name="statusLabel" /> + </item> + <item row="7" column="2" colspan="3" > + <widget class="QProgressBar" name="progressBar" > + <property name="value" > + <number>0</number> + </property> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>closeButton</sender> + <signal>clicked()</signal> + <receiver>InstallDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel" > + <x>330</x> + <y>107</y> + </hint> + <hint type="destinationlabel" > + <x>332</x> + <y>158</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/tools/assistant/tools/assistant/main.cpp b/tools/assistant/tools/assistant/main.cpp new file mode 100644 index 0000000..794be02 --- /dev/null +++ b/tools/assistant/tools/assistant/main.cpp @@ -0,0 +1,318 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QDir> +#include <QtCore/QFileInfo> +#include <QtCore/QLocale> +#include <QtCore/QTranslator> +#include <QtCore/QLibraryInfo> +#include <QtCore/QUrl> +#include <QtCore/QStringList> + +#include <QtGui/QApplication> +#include <QtGui/QDesktopServices> + +#include <QtHelp/QHelpEngineCore> + +#include <QtSql/QSqlDatabase> + +#include "mainwindow.h" +#include "cmdlineparser.h" + +QT_USE_NAMESPACE + +#if defined(USE_STATIC_SQLITE_PLUGIN) + #include <QtPlugin> + Q_IMPORT_PLUGIN(qsqlite) +#endif + +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); + + 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")); + } + + for (int i = currentPages.count(); --i >= 0;) { + if (QUrl(currentPages.at(i)).host() == nsName) { + zoomList.remove(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)); + } +} + +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) + return false; + + user.setCustomValue(QLatin1String("CreationTime"), + callerCollectionCreationTime); + user.setCustomValue(QLatin1String("WindowTitle"), + caller.customValue(QLatin1String("WindowTitle"))); + user.setCustomValue(QLatin1String("LastShownPages"), + caller.customValue(QLatin1String("LastShownPages"))); + 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"))); + + return true; +} + +bool +referencedHelpFilesExistAll(QHelpEngineCore& user, QStringList& nameSpaces) +{ + 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); + } + } + return (counter != nameSpaces.count()) ? false : true; +} + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + a.addLibraryPath(a.applicationDirPath() + QLatin1String("/plugins")); + + CmdLineParser cmd; + CmdLineParser::Result res = cmd.parse(a.arguments()); + 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; + } + } + help.setCustomValue(QLatin1String("DocUpdate"), true); + return 0; + } + + { + 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; + } + } + + if (!cmdCollectionFile.isEmpty()) { + QHelpEngineCore caller(cmdCollectionFile); + if (!caller.setupData()) { + cmd.showMessage(QObject::tr("The specified collection file could " + "not be read!"), true); + return -1; + } + + 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 (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); + } + } + } + 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()); + } + + const QString& locale = QLocale::system().name(); + QString resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath); + + QTranslator translator(0); + translator.load(QLatin1String("assistant_") + locale, resourceDir); + a.installTranslator(&translator); + + QTranslator qtTranslator(0); + qtTranslator.load(QLatin1String("qt_") + locale, resourceDir); + a.installTranslator(&qtTranslator); + + QTranslator qtHelpTranslator(0); + qtHelpTranslator.load(QLatin1String("qt_help_") + locale, resourceDir); + a.installTranslator(&qtHelpTranslator); + + MainWindow w(&cmd); + w.show(); + a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit())); + return a.exec(); +} diff --git a/tools/assistant/tools/assistant/mainwindow.cpp b/tools/assistant/tools/assistant/mainwindow.cpp new file mode 100644 index 0000000..0f246be --- /dev/null +++ b/tools/assistant/tools/assistant/mainwindow.cpp @@ -0,0 +1,1008 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mainwindow.h" +#include "centralwidget.h" +#include "helpviewer.h" +#include "indexwindow.h" +#include "topicchooser.h" +#include "contentwindow.h" +#include "preferencesdialog.h" +#include "bookmarkmanager.h" +#include "remotecontrol.h" +#include "cmdlineparser.h" +#include "aboutdialog.h" +#include "searchwidget.h" +#include "qtdocinstaller.h" + +#include <QtCore/QDir> +#include <QtCore/QTimer> +#include <QtCore/QDebug> +#include <QtCore/QResource> +#include <QtCore/QByteArray> +#include <QtCore/QTextStream> +#include <QtCore/QCoreApplication> + +#include <QtGui/QMenuBar> +#include <QtGui/QAction> +#include <QtGui/QToolBar> +#include <QtGui/QStatusBar> +#include <QtGui/QLabel> +#include <QtGui/QLineEdit> +#include <QtGui/QLayout> +#include <QtGui/QDockWidget> +#include <QtGui/QTreeView> +#include <QtGui/QMessageBox> +#include <QtGui/QFontDatabase> +#include <QtGui/QComboBox> +#include <QtGui/QProgressBar> +#include <QtGui/QDesktopServices> +#include <QtGui/QToolButton> + +#include <QtHelp/QHelpEngine> +#include <QtHelp/QHelpSearchEngine> +#include <QtHelp/QHelpContentModel> +#include <QtHelp/QHelpIndexModel> + +QT_BEGIN_NAMESPACE + +MainWindow::MainWindow(CmdLineParser *cmdLine, QWidget *parent) + : QMainWindow(parent) + , m_toolBarMenu(0) + , m_cmdLine(cmdLine) + , m_searchWidget(0) + , m_progressWidget(0) + , m_qtDocInstaller(0) + , m_connectedInitSignals(false) +{ + if (usesDefaultCollection()) { + MainWindow::collectionFileDirectory(true); + m_helpEngine = new QHelpEngine(MainWindow::defaultHelpCollectionFileName(), + this); + } else { + m_helpEngine = new QHelpEngine(cmdLine->collectionFile(), this); + } + + m_centralWidget = new CentralWidget(m_helpEngine, this); + setCentralWidget(m_centralWidget); + + m_indexWindow = new IndexWindow(m_helpEngine); + 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); + 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); + + QHelpSearchEngine *searchEngine = m_helpEngine->searchEngine(); + connect(searchEngine, SIGNAL(indexingStarted()), this, SLOT(indexingStarted())); + connect(searchEngine, SIGNAL(indexingFinished()), this, SLOT(indexingFinished())); + +#ifdef QT_CLUCENE_SUPPORT + m_centralWidget->createSearchWidget(searchEngine); +#else + QDockWidget *dock = new QDockWidget(tr("Search"), this); + dock->setObjectName(QLatin1String("SearchWindow")); + m_searchWidget = new SearchWidget(searchEngine, this); + dock->setWidget(m_searchWidget); + addDockWidget(Qt::LeftDockWidgetArea, dock); + + connect(m_searchWidget, SIGNAL(requestShowLink(const QUrl&)), + m_centralWidget, SLOT(setSource(const QUrl&))); + connect(m_searchWidget, SIGNAL(requestShowLinkInNewTab(const QUrl&)), + m_centralWidget, SLOT(setSourceInNewTab(const QUrl&))); +#endif + + QString defWindowTitle = tr("Qt Assistant"); + setWindowTitle(defWindowTitle); + + setupActions(); + statusBar()->show(); + + if (initHelpDB()) { + setupFilterToolbar(); + setupAddressToolbar(); + m_bookmarkManager->setupBookmarkModels(); + + setWindowTitle(m_helpEngine->customValue(QLatin1String("WindowTitle"), + defWindowTitle).toString()); + QByteArray iconArray = m_helpEngine->customValue(QLatin1String("ApplicationIcon"), + QByteArray()).toByteArray(); + if (iconArray.size() > 0) { + QPixmap pix; + pix.loadFromData(iconArray); + QIcon appIcon(pix); + qApp->setWindowIcon(appIcon); + } else { + QIcon appIcon(QLatin1String(":/trolltech/assistant/images/assistant-128.png")); + qApp->setWindowIcon(appIcon); + } + + // Show the widget here, otherwise the restore geometry and state won't work + // on x11. + show(); + QByteArray ba(m_helpEngine->customValue(QLatin1String("MainWindow")).toByteArray()); + if (!ba.isEmpty()) + restoreState(ba); + + ba = m_helpEngine->customValue(QLatin1String("MainWindowGeometry")).toByteArray(); + if (!ba.isEmpty()) { + restoreGeometry(ba); + } else { + tabifyDockWidget(contentDock, indexDock); + 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); + } else { + updateApplicationFont(); + } + + updateAboutMenuText(); + + QTimer::singleShot(0, this, SLOT(insertLastPages())); + if (m_cmdLine->enableRemoteControl()) + (void)new RemoteControl(this, m_helpEngine); + + if (m_cmdLine->contents() == CmdLineParser::Show) + showContents(); + else if (m_cmdLine->contents() == CmdLineParser::Hide) + hideContents(); + + if (m_cmdLine->index() == CmdLineParser::Show) + showIndex(); + else if (m_cmdLine->index() == CmdLineParser::Hide) + hideIndex(); + + if (m_cmdLine->bookmarks() == CmdLineParser::Show) + showBookmarks(); + else if (m_cmdLine->bookmarks() == CmdLineParser::Hide) + hideBookmarks(); + + if (m_cmdLine->search() == CmdLineParser::Show) + showSearch(); + else if (m_cmdLine->search() == CmdLineParser::Hide) + hideSearch(); + + if (m_cmdLine->contents() == CmdLineParser::Activate) + showContents(); + else if (m_cmdLine->index() == CmdLineParser::Activate) + showIndex(); + else if (m_cmdLine->bookmarks() == CmdLineParser::Activate) + showBookmarks(); + + if (usesDefaultCollection()) + QTimer::singleShot(0, this, SLOT(lookForNewQtDocumentation())); + else + checkInitState(); + } +} + +MainWindow::~MainWindow() +{ + if (m_qtDocInstaller) + delete m_qtDocInstaller; +} + +bool MainWindow::usesDefaultCollection() const +{ + 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()); + + QMainWindow::closeEvent(e); +} + +bool MainWindow::initHelpDB() +{ + if (!m_helpEngine->setupData()) + return false; + + bool assistantInternalDocRegistered = false; + QString intern(QLatin1String("com.trolltech.com.assistantinternal_")); + foreach (const QString &ns, m_helpEngine->registeredDocumentations()) { + if (ns.startsWith(intern)) { + intern = ns; + assistantInternalDocRegistered = true; + break; + } + } + + const QString &collectionFile = m_helpEngine->collectionFile(); + + QFileInfo fi(collectionFile); + QString helpFile; + QTextStream(&helpFile) << fi.absolutePath() << QDir::separator() + << QLatin1String("assistant.qch.") << (QT_VERSION >> 16) + << QLatin1Char('.') << ((QT_VERSION >> 8) & 0xFF); + + bool needsSetup = false; + if (!assistantInternalDocRegistered || !QFile::exists(helpFile)) { + QFile file(helpFile); + if (file.open(QIODevice::WriteOnly)) { + QResource res(QLatin1String(":/trolltech/assistant/assistant.qch")); + if (file.write((const char*)res.data(), res.size()) != res.size()) + qDebug() << QLatin1String("could not write assistant.qch..."); + + 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); + needsSetup = true; + } + + if (needsSetup) + m_helpEngine->setupData(); + return true; +} + +void MainWindow::lookForNewQtDocumentation() +{ + m_qtDocInstaller = new QtDocInstaller(m_helpEngine->collectionFile()); + connect(m_qtDocInstaller, SIGNAL(errorMessage(const QString&)), + this, SLOT(displayInstallationError(const QString&))); + 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) + statusBar()->showMessage(tr("Looking for Qt Documentation...")); + m_qtDocInstaller->installDocs(); +} + +void MainWindow::displayInstallationError(const QString &errorMessage) +{ + QMessageBox::warning(this, tr("Qt Assistant"), errorMessage); +} + +void MainWindow::qtDocumentationInstalled(bool newDocsInstalled) +{ + if (newDocsInstalled) + m_helpEngine->setupData(); + statusBar()->clearMessage(); + checkInitState(); +} + +void MainWindow::checkInitState() +{ + if (!m_cmdLine->enableRemoteControl()) + return; + + if (m_helpEngine->contentModel()->isCreatingContents() + || m_helpEngine->indexModel()->isCreatingIndex()) { + if (!m_connectedInitSignals) { + connect(m_helpEngine->contentModel(), SIGNAL(contentsCreated()), + this, SLOT(checkInitState())); + connect(m_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); + } + emit initDone(); + } +} + +void MainWindow::insertLastPages() +{ + if (m_cmdLine->url().isValid()) + m_centralWidget->setSource(m_cmdLine->url()); + else + m_centralWidget->setLastShownPages(); + + if (m_cmdLine->search() == CmdLineParser::Activate) + showSearch(); +} + +void MainWindow::setupActions() +{ + QString system = QLatin1String("win"); +#ifdef Q_OS_MAC + system = QLatin1String("mac"); + setUnifiedTitleAndToolBarOnMac(true); +#endif + + QMenu *menu = menuBar()->addMenu(tr("&File")); + + m_pageSetupAction = menu->addAction(tr("Page Set&up..."), m_centralWidget, SLOT(pageSetup())); + m_printPreviewAction = menu->addAction(tr("Print Preview..."), m_centralWidget, SLOT(printPreview())); + m_printAction = menu->addAction(tr("&Print..."), m_centralWidget, SLOT(print())); + m_printAction->setIcon(QIcon( + QString::fromUtf8(":/trolltech/assistant/images/%1/print.png").arg(system))); + m_printAction->setShortcut(tr("CTRL+P")); + + menu->addSeparator(); + + m_newTabAction = menu->addAction(tr("New &Tab"), m_centralWidget, SLOT(newTab())); + m_newTabAction->setShortcut(tr("CTRL+T")); + m_closeTabAction = menu->addAction(tr("&Close Tab"), m_centralWidget, SLOT(closeTab())); + m_closeTabAction->setShortcut(tr("CTRL+W")); + + QAction *tmp = menu->addAction(tr("&Quit"), this, SLOT(close())); + tmp->setShortcut(tr("CTRL+Q")); + tmp->setMenuRole(QAction::QuitRole); + + menu = menuBar()->addMenu(tr("&Edit")); + m_copyAction = menu->addAction(tr("&Copy selected Text"), + m_centralWidget, SLOT(copySelection())); + m_copyAction->setIcon(QIcon( + QString::fromUtf8(":/trolltech/assistant/images/%1/editcopy.png").arg(system))); + m_copyAction->setShortcut(tr("Ctrl+C")); + m_copyAction->setEnabled(false); + + m_findAction = menu->addAction(tr("&Find in Text..."), + m_centralWidget, SLOT(showTextSearch())); + m_findAction->setIcon(QIcon( + QString::fromUtf8(":/trolltech/assistant/images/%1/find.png").arg(system))); + m_findAction->setShortcut(tr("Ctrl+F")); + m_findAction->setShortcut(QKeySequence::Find); + + QAction *findNextAction = menu->addAction(tr("Find &Next"), + m_centralWidget, SLOT(findNext())); + findNextAction->setShortcuts(QList<QKeySequence>() << QKeySequence(tr("F3")) + << QKeySequence(tr("CTRL+G"))); + + QAction *findPreviousAction = menu->addAction(tr("Find &Previous"), + m_centralWidget, SLOT(findPrevious())); + findPreviousAction->setShortcuts(QList<QKeySequence>() << + QKeySequence(tr("Shift+F3")) << QKeySequence(tr("CTRL+SHIFT+G"))); + + menu->addSeparator(); + tmp = menu->addAction(tr("Preferences..."), this, SLOT(showPreferences())); + tmp->setMenuRole(QAction::PreferencesRole); + + m_viewMenu = menuBar()->addMenu(tr("&View")); + m_zoomInAction = m_viewMenu->addAction(tr("Zoom &in"), + m_centralWidget, SLOT(zoomIn())); + m_zoomInAction->setIcon(QIcon( + QString::fromUtf8(":/trolltech/assistant/images/%1/zoomin.png").arg(system))); + m_zoomInAction->setShortcut(tr("Ctrl++")); + + m_zoomOutAction = m_viewMenu->addAction(tr("Zoom &out"), + m_centralWidget, SLOT(zoomOut())); + m_zoomOutAction->setIcon(QIcon( + QString::fromUtf8(":/trolltech/assistant/images/%1/zoomout.png").arg(system))); + m_zoomOutAction->setShortcut(tr("Ctrl+-")); + + m_resetZoomAction = m_viewMenu->addAction(tr("Normal &Size"), + m_centralWidget, SLOT(resetZoom())); + m_resetZoomAction->setIcon(QIcon( + QString::fromUtf8(":/trolltech/assistant/images/%1/resetzoom.png").arg(system))); + m_resetZoomAction->setShortcut(tr("Ctrl+0")); + + m_viewMenu->addSeparator(); + + m_viewMenu->addAction(tr("Contents"), this, + SLOT(showContents()), QKeySequence(tr("ALT+C"))); + m_viewMenu->addAction(tr("Index"), this, + SLOT(showIndex()), QKeySequence(tr("ALT+I"))); + m_viewMenu->addAction(tr("Bookmarks"), this, + SLOT(showBookmarks()), QKeySequence(tr("ALT+O"))); + m_viewMenu->addAction(tr("Search"), this, + SLOT(showSearch()), QKeySequence(tr("ALT+S"))); + + menu = menuBar()->addMenu(tr("&Go")); + m_homeAction = menu->addAction(tr("&Home"), + m_centralWidget, SLOT(home())); + m_homeAction->setShortcut(tr("Ctrl+Home")); + m_homeAction->setIcon(QIcon( + QString::fromUtf8(":/trolltech/assistant/images/%1/home.png").arg(system))); + + m_backAction = menu->addAction(tr("&Back"), + m_centralWidget, SLOT(backward())); + m_backAction->setEnabled(false); + m_backAction->setShortcuts(QList<QKeySequence>() + << QKeySequence(Qt::CTRL|Qt::Key_Left) << QKeySequence::Back); + m_backAction->setIcon(QIcon( + QString::fromUtf8(":/trolltech/assistant/images/%1/previous.png").arg(system))); + + m_nextAction = menu->addAction(tr("&Forward"), + m_centralWidget, SLOT(forward())); + m_nextAction->setEnabled(false); + m_nextAction->setShortcuts(QList<QKeySequence>() + << QKeySequence(Qt::CTRL|Qt::Key_Right) << QKeySequence::Forward); + m_nextAction->setIcon(QIcon( + QString::fromUtf8(":/trolltech/assistant/images/%1/next.png").arg(system))); + + m_syncAction = menu->addAction(tr("Sync with Table of Contents"), + this, SLOT(syncContents())); + m_syncAction->setIcon(QIcon( + QString::fromUtf8(":/trolltech/assistant/images/%1/synctoc.png").arg(system))); + + menu->addSeparator(); + + tmp = menu->addAction(tr("Next Page"), m_centralWidget, SLOT(nextPage())); + tmp->setShortcuts(QList<QKeySequence>() << QKeySequence(tr("Ctrl+Alt+Right")) + << QKeySequence(Qt::CTRL + Qt::Key_PageDown)); + + tmp = menu->addAction(tr("Previous Page"), + m_centralWidget, SLOT(previousPage())); + tmp->setShortcuts(QList<QKeySequence>() << QKeySequence(tr("Ctrl+Alt+Left")) + << QKeySequence(Qt::CTRL + Qt::Key_PageUp)); + + menu = menuBar()->addMenu(tr("&Bookmarks")); + tmp = menu->addAction(tr("Add Bookmark..."), this, SLOT(addBookmark())); + tmp->setShortcut(tr("CTRL+D")); + + menu = menuBar()->addMenu(tr("&Help")); + m_aboutAction = menu->addAction(tr("About..."), this, SLOT(showAboutDialog())); + m_aboutAction->setMenuRole(QAction::AboutRole); + + QToolBar *navigationBar = addToolBar(tr("Navigation Toolbar")); + navigationBar->setObjectName(QLatin1String("NavigationToolBar")); + navigationBar->addAction(m_backAction); + navigationBar->addAction(m_nextAction); + navigationBar->addAction(m_homeAction); + navigationBar->addAction(m_syncAction); + QAction *sep = navigationBar->addSeparator(); + navigationBar->addAction(m_copyAction); + navigationBar->addAction(m_printAction); + navigationBar->addAction(m_findAction); + QAction *sep2 = navigationBar->addSeparator(); + navigationBar->addAction(m_zoomInAction); + navigationBar->addAction(m_zoomOutAction); + navigationBar->addAction(m_resetZoomAction); + + QList<QAction*> actionList; + actionList << m_backAction << m_nextAction << m_homeAction; + actionList << sep << m_zoomInAction << m_zoomOutAction; + actionList << sep2 << m_copyAction << m_printAction << m_findAction; + m_centralWidget->setGlobalActions(actionList); + +#if defined(Q_WS_MAC) + QMenu *windowMenu = new QMenu(tr("&Window"), this); + menuBar()->insertMenu(menu->menuAction(), windowMenu); + windowMenu->addAction(tr("Minimize"), this, + SLOT(showMinimized()), QKeySequence(tr("Ctrl+M"))); + windowMenu->addAction(tr("Zoom"), this, + SLOT(showMaximized())); +#endif + + // content viewer connections + connect(m_centralWidget, SIGNAL(copyAvailable(bool)), + this, SLOT(copyAvailable(bool))); + connect(m_centralWidget, SIGNAL(currentViewerChanged()), + this, SLOT(updateNavigationItems())); + connect(m_centralWidget, SIGNAL(forwardAvailable(bool)), + this, SLOT(updateNavigationItems())); + connect(m_centralWidget, SIGNAL(backwardAvailable(bool)), + this, SLOT(updateNavigationItems())); + connect(m_centralWidget, SIGNAL(highlighted(const QString&)), + statusBar(), SLOT(showMessage(const QString&))); + connect(m_centralWidget, SIGNAL(addNewBookmark(const QString&, + const QString&)), this, SLOT(addNewBookmark(const QString&, const QString&))); + + // bookmarks + connect(m_bookmarkWidget, SIGNAL(requestShowLink(const QUrl&)), + m_centralWidget, SLOT(setSource(const QUrl&))); + connect(m_bookmarkWidget, SIGNAL(escapePressed()), + this, SLOT(activateCurrentCentralWidgetTab())); + + // index window + connect(m_indexWindow, SIGNAL(linkActivated(const QUrl&)), + m_centralWidget, SLOT(setSource(const QUrl&))); + connect(m_indexWindow, SIGNAL(linksActivated(const QMap<QString, QUrl>&, const QString&)), + this, SLOT(showTopicChooser(const QMap<QString, QUrl>&, const QString&))); + connect(m_indexWindow, SIGNAL(escapePressed()), + this, SLOT(activateCurrentCentralWidgetTab())); + + // content window + connect(m_contentWindow, SIGNAL(linkActivated(const QUrl&)), + m_centralWidget, SLOT(setSource(const QUrl&))); + connect(m_contentWindow, SIGNAL(escapePressed()), + this, SLOT(activateCurrentCentralWidgetTab())); + +#if defined(QT_NO_PRINTER) + m_pageSetupAction->setVisible(false); + m_printPreviewAction->setVisible(false); + m_printAction->setVisible(false); +#endif +} + +QMenu *MainWindow::toolBarMenu() +{ + if (!m_toolBarMenu) { + m_viewMenu->addSeparator(); + m_toolBarMenu = m_viewMenu->addMenu(tr("Toolbars")); + } + return m_toolBarMenu; +} + +void MainWindow::setupFilterToolbar() +{ + if (!m_helpEngine-> + customValue(QLatin1String("EnableFilterFunctionality"), true).toBool()) + return; + + m_filterCombo = new QComboBox(this); + m_filterCombo->setMinimumWidth(QFontMetrics(QFont()). + width(QLatin1String("MakeTheComboBoxWidthEnough"))); + + QToolBar *filterToolBar = addToolBar(tr("Filter Toolbar")); + filterToolBar->setObjectName(QLatin1String("FilterToolBar")); + filterToolBar->addWidget(new QLabel(tr("Filtered by:").append(QLatin1String(" ")), this)); + filterToolBar->addWidget(m_filterCombo); + + if (m_helpEngine->customValue(QLatin1String("HideFilterFunctionality"), true).toBool()) + filterToolBar->hide(); + toolBarMenu()->addAction(filterToolBar->toggleViewAction()); + + connect(m_helpEngine, SIGNAL(setupFinished()), + this, SLOT(setupFilterCombo())); + connect(m_filterCombo, SIGNAL(activated(const QString&)), + this, SLOT(filterDocumentation(const QString&))); + + setupFilterCombo(); +} + +void MainWindow::setupAddressToolbar() +{ + if (!m_helpEngine->customValue(QLatin1String("EnableAddressBar"), true).toBool()) + return; + + m_addressLineEdit = new QLineEdit(this); + QToolBar *addressToolBar = addToolBar(tr("Address Toolbar")); + addressToolBar->setObjectName(QLatin1String("AddressToolBar")); + insertToolBarBreak(addressToolBar); + + addressToolBar->addWidget(new QLabel(tr("Address:").append(QLatin1String(" ")), this)); + addressToolBar->addWidget(m_addressLineEdit); + + if (m_helpEngine->customValue(QLatin1String("HideAddressBar"), true).toBool()) + addressToolBar->hide(); + toolBarMenu()->addAction(addressToolBar->toggleViewAction()); + + // address lineedit + connect(m_addressLineEdit, SIGNAL(returnPressed()), + this, SLOT(gotoAddress())); + connect(m_centralWidget, SIGNAL(currentViewerChanged()), + this, SLOT(showNewAddress())); + connect(m_centralWidget, SIGNAL(sourceChanged(const QUrl&)), + this, SLOT(showNewAddress(const QUrl&))); +} + +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; + } + } + if (!trStr.isEmpty()) + m_aboutAction->setText(trStr); + } + } +} + +void MainWindow::showNewAddress() +{ + showNewAddress(m_centralWidget->currentSource()); +} + +void MainWindow::showNewAddress(const QUrl &url) +{ + m_addressLineEdit->setText(url.toString()); +} + +void MainWindow::addBookmark() +{ + addNewBookmark(m_centralWidget->currentTitle(), m_centralWidget->currentSource().toString()); +} + +void MainWindow::gotoAddress() +{ + m_centralWidget->setSource(m_addressLineEdit->text()); +} + +void MainWindow::updateNavigationItems() +{ + bool hasCurrentViewer = m_centralWidget->isHomeAvailable(); + m_copyAction->setEnabled(m_centralWidget->hasSelection()); + m_homeAction->setEnabled(hasCurrentViewer); + m_syncAction->setEnabled(hasCurrentViewer); + m_printPreviewAction->setEnabled(hasCurrentViewer); + m_printAction->setEnabled(hasCurrentViewer); + m_nextAction->setEnabled(m_centralWidget->isForwardAvailable()); + m_backAction->setEnabled(m_centralWidget->isBackwardAvailable()); + m_closeTabAction->setEnabled(hasCurrentViewer); + m_newTabAction->setEnabled(hasCurrentViewer); +} + +void MainWindow::showTopicChooser(const QMap<QString, QUrl> &links, + const QString &keyword) +{ + TopicChooser tc(this, keyword, links); + if (tc.exec() == QDialog::Accepted) { + m_centralWidget->setSource(tc.link()); + } +} + +void MainWindow::showPreferences() +{ + PreferencesDialog dia(m_helpEngine, this); + + connect(&dia, SIGNAL(updateApplicationFont()), + this, SLOT(updateApplicationFont())); + connect(&dia, SIGNAL(updateBrowserFont()), + m_centralWidget, SLOT(updateBrowserFont())); + + dia.showDialog(); +} + +void MainWindow::syncContents() +{ + qApp->setOverrideCursor(QCursor(Qt::WaitCursor)); + const QUrl url = m_centralWidget->currentSource(); + showContents(); + if (!m_contentWindow->syncToContent(url)) + statusBar()->showMessage( + tr("Could not find the associated content item."), 3000); + qApp->restoreOverrideCursor(); +} + +void MainWindow::copyAvailable(bool yes) +{ + m_copyAction->setEnabled(yes); +} + +void MainWindow::addNewBookmark(const QString &title, const QString &url) +{ + if (url.isEmpty()) + return; + + m_bookmarkManager->showBookmarkDialog(this, title, url); +} + +void MainWindow::showAboutDialog() +{ + 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; + } + } + } + } + + AboutDialog aboutDia(this); + + QByteArray iconArray; + if (!contents.isEmpty()) { + iconArray = m_helpEngine->customValue(QLatin1String("AboutIcon"), + QByteArray()).toByteArray(); + QByteArray resources = m_helpEngine->customValue(QLatin1String("AboutImages"), + QByteArray()).toByteArray(); + QPixmap pix; + pix.loadFromData(iconArray); + aboutDia.setText(QString::fromUtf8(contents), resources); + if (!pix.isNull()) + aboutDia.setPixmap(pix); + aboutDia.setWindowTitle(aboutDia.documentTitle()); + } else { +#if QT_EDITION == QT_EDITION_OPENSOURCE + QString edition = tr("Open Source Edition"); + QString info = tr("This version of Qt Assistant is part of the Qt Open Source Edition, for use " + "in the development of Open Source applications. " + "Qt is a comprehensive C++ framework for cross-platform application " + "development."); + QString moreInfo = tr("You need a commercial Qt license for development of proprietary (closed " + "source) applications. Please see <a href=\"http://qtsoftware.com/company/about/businessmodel" + "\">http://qtsoftware.com/company/about/businessmodel</a> for an overview of Qt licensing."); +#else + QString edition; + QString info; + QString moreInfo(tr("This program is licensed to you under the terms of the " + "Qt Commercial License Agreement. For details, see the file LICENSE " + "that came with this software distribution.")); + +#endif + QByteArray resources; + aboutDia.setText(QString::fromLatin1("<center>" + "<h3>%1</h3>" + "<p>Version %2 %3</p></center>" + "<p>%4</p>" + "<p>%5</p>" + "<p>Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).</p>" + "<p>The program is provided AS IS with NO WARRANTY OF ANY KIND," + " INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A" + " PARTICULAR PURPOSE.<p/>") + .arg(tr("Qt Assistant")).arg(QLatin1String(QT_VERSION_STR)) + .arg(edition).arg(info).arg(moreInfo), resources); + aboutDia.setPixmap(QString::fromLatin1(":/trolltech/assistant/images/assistant-128.png")); + } + if (aboutDia.windowTitle().isEmpty()) + aboutDia.setWindowTitle(tr("About %1").arg(windowTitle())); + aboutDia.exec(); +} + +void MainWindow::showContents() +{ + activateDockWidget(m_contentWindow); +} + +void MainWindow::showIndex() +{ + activateDockWidget(m_indexWindow); +} + +void MainWindow::showBookmarks() +{ + activateDockWidget(m_bookmarkWidget); +} + +void MainWindow::activateDockWidget(QWidget *w) +{ + w->parentWidget()->show(); + w->parentWidget()->raise(); + w->setFocus(); +} + +void MainWindow::hideContents() +{ + m_contentWindow->parentWidget()->hide(); +} + +void MainWindow::hideIndex() +{ + m_indexWindow->parentWidget()->hide(); +} + +void MainWindow::hideBookmarks() +{ + m_bookmarkWidget->parentWidget()->hide(); +} + +void MainWindow::setIndexString(const QString &str) +{ + m_indexWindow->setSearchLineEditText(str); +} + +void MainWindow::activateCurrentBrowser() +{ + CentralWidget *cw = CentralWidget::instance(); + if (cw) { + cw->activateTab(true); + } +} + +void MainWindow::activateCurrentCentralWidgetTab() +{ + m_centralWidget->activateTab(); +} + +void MainWindow::showSearch() +{ + if (m_searchWidget) + activateDockWidget(m_searchWidget); + else + m_centralWidget->activateSearch(); +} + +void MainWindow::hideSearch() +{ + if (m_searchWidget) { + m_searchWidget->parentWidget()->parentWidget()->hide(); + } else { + m_centralWidget->removeSearchWidget(); + } +} + +void MainWindow::updateApplicationFont() +{ + QFont font = qApp->font(); + if (m_helpEngine->customValue(QLatin1String("useAppFont")).toBool()) + font = qVariantValue<QFont>(m_helpEngine->customValue(QLatin1String("appFont"))); + + qApp->setFont(font, "QWidget"); +} + +void MainWindow::setupFilterCombo() +{ + QString curFilter = m_filterCombo->currentText(); + if (curFilter.isEmpty()) + curFilter = m_helpEngine->currentFilter(); + m_filterCombo->clear(); + m_filterCombo->addItems(m_helpEngine->customFilters()); + int idx = m_filterCombo->findText(curFilter); + if (idx < 0) + idx = 0; + m_filterCombo->setCurrentIndex(idx); +} + +void MainWindow::filterDocumentation(const QString &customFilter) +{ + m_helpEngine->setCurrentFilter(customFilter); +} + +void MainWindow::expandTOC(int depth) +{ + m_contentWindow->expandToDepth(depth); +} + +void MainWindow::indexingStarted() +{ + m_progressWidget = new QWidget(); + QLayout* hlayout = new QHBoxLayout(m_progressWidget); + + QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); + + QLabel *label = new QLabel(tr("Updating search index")); + label->setSizePolicy(sizePolicy); + hlayout->addWidget(label); + + QProgressBar *progressBar = new QProgressBar(); + progressBar->setRange(0, 0); + progressBar->setTextVisible(false); + progressBar->setSizePolicy(sizePolicy); + + hlayout->setSpacing(6); + hlayout->setMargin(0); + hlayout->addWidget(progressBar); + + statusBar()->addPermanentWidget(m_progressWidget); +} + +void MainWindow::indexingFinished() +{ + 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) +{ + QString collectionPath = QDesktopServices::storageLocation(QDesktopServices::DataLocation); + if (collectionPath.isEmpty()) { + if (cacheDir.isEmpty()) + collectionPath = QDir::homePath() + QDir::separator() + + QLatin1String(".assistant"); + else + collectionPath = QDir::homePath() + QLatin1String("/.") + + cacheDir; + } else { + if (cacheDir.isEmpty()) + collectionPath = collectionPath + QLatin1String("/Trolltech/Assistant"); + else + collectionPath = collectionPath + QDir::separator() + + cacheDir; + } + collectionPath = QDir::cleanPath(collectionPath); + if (createDir) { + QDir dir; + if (!dir.exists(collectionPath)) + dir.mkpath(collectionPath); + } + return collectionPath; +} + +QString MainWindow::defaultHelpCollectionFileName() +{ + return collectionFileDirectory() + QDir::separator() + + QString(QLatin1String("qthelpcollection_%1.qhc")). + arg(QLatin1String(QT_VERSION_STR)); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/mainwindow.h b/tools/assistant/tools/assistant/mainwindow.h new file mode 100644 index 0000000..8b87b7b --- /dev/null +++ b/tools/assistant/tools/assistant/mainwindow.h @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include <QtCore/QUrl> +#include <QtGui/QMainWindow> + +QT_BEGIN_NAMESPACE + +class QAction; +class QLineEdit; +class QComboBox; +class QMenu; + +class IndexWindow; +class QHelpEngineCore; +class QHelpEngine; +class CentralWidget; +class ContentWindow; +class BookmarkManager; +class BookmarkWidget; +class CmdLineParser; +class QtDocInstaller; + +class SearchWidget; + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(CmdLineParser *cmdLine, QWidget *parent = 0); + ~MainWindow(); + + static void activateCurrentBrowser(); + static QString collectionFileDirectory(bool createDir = false, + const QString &cacheDir = QString()); + static QString defaultHelpCollectionFileName(); + +public: + void hideContents(); + void hideIndex(); + void hideBookmarks(); + void hideSearch(); + void setIndexString(const QString &str); + void expandTOC(int depth); + bool usesDefaultCollection() const; + +signals: + void initDone(); + +public slots: + void showContents(); + void showIndex(); + void showBookmarks(); + void showSearch(); + void syncContents(); + void activateCurrentCentralWidgetTab(); + +private slots: + void insertLastPages(); + void addBookmark(); + void gotoAddress(); + void showPreferences(); + void showNewAddress(); + void showAboutDialog(); + void copyAvailable(bool yes); + void updateNavigationItems(); + 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); + void setupFilterCombo(); + void lookForNewQtDocumentation(); + void indexingStarted(); + void indexingFinished(); + void displayInstallationError(const QString &errorMessage); + void qtDocumentationInstalled(bool newDocsInstalled); + void checkInitState(); + +private: + bool initHelpDB(); + void setupActions(); + void closeEvent(QCloseEvent *e); + void activateDockWidget(QWidget *w); + void updateAboutMenuText(); + void setupFilterToolbar(); + void setupAddressToolbar(); + QMenu *toolBarMenu(); + QWidget *setupBookmarkWidget(); + + QHelpEngine *m_helpEngine; + CentralWidget *m_centralWidget; + IndexWindow *m_indexWindow; + ContentWindow *m_contentWindow; + BookmarkWidget *m_bookmarkWidget; + BookmarkManager *m_bookmarkManager; + QLineEdit *m_addressLineEdit; + QComboBox *m_filterCombo; + + QAction *m_backAction; + QAction *m_nextAction; + QAction *m_homeAction; + QAction *m_syncAction; + QAction *m_copyAction; + QAction *m_findAction; + QAction *m_printAction; + QAction *m_printPreviewAction; + QAction *m_pageSetupAction; + QAction *m_zoomInAction; + QAction *m_zoomOutAction; + QAction *m_resetZoomAction; + QAction *m_aboutAction; + QAction *m_closeTabAction; + QAction *m_newTabAction; + + QMenu *m_viewMenu; + QMenu *m_toolBarMenu; + + CmdLineParser *m_cmdLine; + SearchWidget *m_searchWidget; + + QWidget *m_progressWidget; + QtDocInstaller *m_qtDocInstaller; + + bool m_connectedInitSignals; +}; + +QT_END_NAMESPACE + +#endif // MAINWINDOW_H diff --git a/tools/assistant/tools/assistant/preferencesdialog.cpp b/tools/assistant/tools/assistant/preferencesdialog.cpp new file mode 100644 index 0000000..094bd9c --- /dev/null +++ b/tools/assistant/tools/assistant/preferencesdialog.cpp @@ -0,0 +1,453 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "preferencesdialog.h" +#include "filternamedialog.h" +#include "installdialog.h" +#include "fontpanel.h" +#include "centralwidget.h" + +#include <QtAlgorithms> + +#include <QtGui/QHeaderView> +#include <QtGui/QFileDialog> +#include <QtGui/QMessageBox> +#include <QtGui/QMenu> +#include <QtGui/QFontDatabase> + +#include <QtHelp/QHelpEngineCore> + +QT_BEGIN_NAMESPACE + +PreferencesDialog::PreferencesDialog(QHelpEngineCore *helpEngine, QWidget *parent) + : QDialog(parent) + , m_appFontChanged(false) + , m_browserFontChanged(false) +{ + m_helpEngine = helpEngine; + m_ui.setupUi(this); + + connect(m_ui.buttonBox->button(QDialogButtonBox::Ok), + SIGNAL(clicked()), this, SLOT(applyChanges())); + connect(m_ui.buttonBox->button(QDialogButtonBox::Cancel), + SIGNAL(clicked()), this, SLOT(reject())); + + m_hideFiltersTab = !m_helpEngine->customValue(QLatin1String("EnableFilterFunctionality"), + true).toBool(); + m_hideDocsTab = !m_helpEngine->customValue(QLatin1String("EnableDocumentationManager"), + true).toBool(); + + if (!m_hideFiltersTab) { + m_ui.attributeWidget->header()->hide(); + m_ui.attributeWidget->setRootIsDecorated(false); + connect(m_ui.attributeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)), + this, SLOT(updateFilterMap())); + + connect(m_ui.filterWidget, + SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), + this, SLOT(updateAttributes(QListWidgetItem*))); + + connect(m_ui.filterAddButton, SIGNAL(clicked()), + this, SLOT(addFilter())); + connect(m_ui.filterRemoveButton, SIGNAL(clicked()), + this, SLOT(removeFilter())); + + updateFilterPage(); + } else { + m_ui.tabWidget->removeTab(m_ui.tabWidget->indexOf(m_ui.filtersTab)); + } + + if (!m_hideDocsTab) { + connect(m_ui.docAddButton, SIGNAL(clicked()), this, + SLOT(addDocumentationLocal())); + connect(m_ui.docRemoveButton, SIGNAL(clicked()), this, + SLOT(removeDocumentation())); + + m_docsBackup = m_helpEngine->registeredDocumentations(); + m_ui.registeredDocsListWidget->addItems(m_docsBackup); + } else { + m_ui.tabWidget->removeTab(m_ui.tabWidget->indexOf(m_ui.docsTab)); + } + updateFontSettingsPage(); + updateOptionsPage(); +} + +PreferencesDialog::~PreferencesDialog() +{ + if (m_appFontChanged) { + m_helpEngine->setCustomValue(QLatin1String("appFont"), m_appFontPanel->selectedFont()); + m_helpEngine->setCustomValue(QLatin1String("useAppFont"), m_appFontPanel->isChecked()); + m_helpEngine->setCustomValue(QLatin1String("appWritingSystem"), m_appFontPanel->writingSystem()); + } + + if (m_browserFontChanged) { + m_helpEngine->setCustomValue(QLatin1String("browserFont"), m_browserFontPanel->selectedFont()); + m_helpEngine->setCustomValue(QLatin1String("useBrowserFont"), m_browserFontPanel->isChecked()); + m_helpEngine->setCustomValue(QLatin1String("browserWritingSystem"), m_browserFontPanel->writingSystem()); + } + + if (m_appFontChanged || m_browserFontChanged) { + emit updateApplicationFont(); + emit updateBrowserFont(); + } + + if (!m_ui.homePageLineEdit->text().isEmpty()) + m_helpEngine->setCustomValue(QLatin1String("homepage"), m_ui.homePageLineEdit->text()); +} + +void PreferencesDialog::showDialog() +{ + if (exec() != Accepted) + m_appFontChanged = m_browserFontChanged = false; +} + +void PreferencesDialog::updateFilterPage() +{ + if (!m_helpEngine) + return; + + m_ui.filterWidget->clear(); + m_ui.attributeWidget->clear(); + + QHelpEngineCore help(m_helpEngine->collectionFile(), 0); + help.setupData(); + m_filterMapBackup.clear(); + const QStringList filters = help.customFilters(); + foreach (const QString &filter, filters) { + QStringList atts = help.filterAttributes(filter); + m_filterMapBackup.insert(filter, atts); + if (!m_filterMap.contains(filter)) + m_filterMap.insert(filter, atts); + } + + m_ui.filterWidget->addItems(m_filterMap.keys()); + + foreach (const QString &a, help.filterAttributes()) + new QTreeWidgetItem(m_ui.attributeWidget, QStringList() << a); + + if (m_filterMap.keys().count()) + m_ui.filterWidget->setCurrentRow(0); +} + +void PreferencesDialog::updateAttributes(QListWidgetItem *item) +{ + QStringList checkedList; + if (item) + checkedList = m_filterMap.value(item->text()); + QTreeWidgetItem *itm; + for (int i=0; i<m_ui.attributeWidget->topLevelItemCount(); ++i) { + itm = m_ui.attributeWidget->topLevelItem(i); + if (checkedList.contains(itm->text(0))) + itm->setCheckState(0, Qt::Checked); + else + itm->setCheckState(0, Qt::Unchecked); + } +} + +void PreferencesDialog::updateFilterMap() +{ + if (!m_ui.filterWidget->currentItem()) + return; + QString filter = m_ui.filterWidget->currentItem()->text(); + if (!m_filterMap.contains(filter)) + return; + + QStringList newAtts; + QTreeWidgetItem *itm = 0; + for (int i=0; i<m_ui.attributeWidget->topLevelItemCount(); ++i) { + itm = m_ui.attributeWidget->topLevelItem(i); + if (itm->checkState(0) == Qt::Checked) + newAtts.append(itm->text(0)); + } + m_filterMap[filter] = newAtts; +} + +void PreferencesDialog::addFilter() +{ + FilterNameDialog dia(this); + if (dia.exec() == QDialog::Rejected) + return; + + QString filterName = dia.filterName(); + if (!m_filterMap.contains(filterName)) { + m_filterMap.insert(filterName, QStringList()); + m_ui.filterWidget->addItem(filterName); + } + + QList<QListWidgetItem*> lst = m_ui.filterWidget + ->findItems(filterName, Qt::MatchCaseSensitive); + m_ui.filterWidget->setCurrentItem(lst.first()); +} + +void PreferencesDialog::removeFilter() +{ + QListWidgetItem *item = m_ui.filterWidget + ->takeItem(m_ui.filterWidget->currentRow()); + if (!item) + return; + + m_filterMap.remove(item->text()); + m_removedFilters.append(item->text()); + delete item; + if (m_ui.filterWidget->count()) + m_ui.filterWidget->setCurrentRow(0); +} + +void PreferencesDialog::addDocumentationLocal() +{ + const QStringList fileNames = QFileDialog::getOpenFileNames(this, + tr("Add Documentation"), QString(), tr("Qt Compressed Help Files (*.qch)")); + if (fileNames.isEmpty()) + return; + + foreach (const QString &fileName, fileNames) { + const QString ns = QHelpEngineCore::namespaceName(fileName); + if (ns.isEmpty()) { + QMessageBox::warning(this, tr("Add Documentation"), + tr("The specified file is not a valid Qt Help File!")); + continue; + } + + if (m_ui.registeredDocsListWidget->findItems(ns, Qt::MatchFixedString).count()) { + QMessageBox::warning(this, tr("Add Documentation"), + tr("The namespace %1 is already registered!").arg(ns)); + continue; + } + + m_helpEngine->registerDocumentation(fileName); + m_ui.registeredDocsListWidget->addItem(ns); + m_regDocs.append(ns); + m_unregDocs.removeAll(ns); + } + updateFilterPage(); +} + +void PreferencesDialog::removeDocumentation() +{ + bool foundBefore = false; + CentralWidget* widget = CentralWidget::instance(); + QMap<int, QString> openedDocList = widget->currentSourceFileList(); + QStringList values(openedDocList.values()); + + QList<QListWidgetItem*> l = m_ui.registeredDocsListWidget->selectedItems(); + foreach (QListWidgetItem* item, l) { + const QString& ns = item->text(); + if (!foundBefore && values.contains(ns)) { + if (0 == QMessageBox::information(this, tr("Remove Documentation"), + tr("Some documents currently opened in Assistant reference the " + "documentation you are attempting to remove. Removing the " + "documentation will close those documents."), tr("Cancel"), + tr("OK"))) return; + foundBefore = true; + } + + m_unregDocs.append(ns); + m_TabsToClose += openedDocList.keys(ns); + delete m_ui.registeredDocsListWidget->takeItem( + m_ui.registeredDocsListWidget->row(item)); + } + + if (m_ui.registeredDocsListWidget->count()) { + m_ui.registeredDocsListWidget->setCurrentRow(0, + QItemSelectionModel::ClearAndSelect); + } +} + +void PreferencesDialog::applyChanges() +{ + bool filtersWereChanged = false; + if (!m_hideFiltersTab) { + if (m_filterMap.count() != m_filterMapBackup.count()) { + filtersWereChanged = true; + } else { + QMapIterator<QString, QStringList> it(m_filterMapBackup); + while (it.hasNext() && !filtersWereChanged) { + it.next(); + if (!m_filterMap.contains(it.key())) { + filtersWereChanged = true; + } else { + QStringList a = it.value(); + QStringList b = m_filterMap.value(it.key()); + if (a.count() != b.count()) { + filtersWereChanged = true; + } else { + QStringList::const_iterator i(a.constBegin()); + while (i != a.constEnd()) { + if (!b.contains(*i)) { + filtersWereChanged = true; + break; + } + ++i; + } + } + } + } + } + } + + if (filtersWereChanged) { + foreach (const QString &filter, m_removedFilters) + m_helpEngine->removeCustomFilter(filter); + QMapIterator<QString, QStringList> it(m_filterMap); + while (it.hasNext()) { + it.next(); + m_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 (m_unregDocs.count()) { + foreach (const QString &doc, m_unregDocs) + m_helpEngine->unregisterDocumentation(doc); + } + + if (filtersWereChanged || m_regDocs.count() || m_unregDocs.count()) + m_helpEngine->setupData(); + + accept(); +} + +void PreferencesDialog::updateFontSettingsPage() +{ + m_browserFontPanel = new FontPanel(this); + m_browserFontPanel->setCheckable(true); + m_ui.stackedWidget_2->insertWidget(0, m_browserFontPanel); + + m_appFontPanel = new FontPanel(this); + m_appFontPanel->setCheckable(true); + m_ui.stackedWidget_2->insertWidget(1, m_appFontPanel); + + m_ui.stackedWidget_2->setCurrentIndex(0); + + const QString customSettings(tr("Use custom settings")); + QFont font = qVariantValue<QFont>(m_helpEngine->customValue(QLatin1String("appFont"))); + QFontDatabase::WritingSystem writingSystem = static_cast<QFontDatabase::WritingSystem> + (m_helpEngine->customValue(QLatin1String("appWritingSystem")).toInt()); + + m_appFontPanel->setTitle(customSettings); + m_appFontPanel->setSelectedFont(font); + m_appFontPanel->setWritingSystem(writingSystem); + m_appFontPanel->setChecked(m_helpEngine->customValue(QLatin1String("useAppFont")).toBool()); + + QFont font2 = qVariantValue<QFont>(m_helpEngine->customValue(QLatin1String("browserFont"))); + writingSystem = static_cast<QFontDatabase::WritingSystem> + (m_helpEngine->customValue(QLatin1String("browserWritingSystem")).toInt()); + + m_browserFontPanel->setTitle(customSettings); + m_browserFontPanel->setSelectedFont(font2); + m_browserFontPanel->setWritingSystem(writingSystem); + m_browserFontPanel->setChecked(m_helpEngine->customValue(QLatin1String("useBrowserFont")).toBool()); + + connect(m_appFontPanel, SIGNAL(toggled(bool)), this, SLOT(appFontSettingToggled(bool))); + connect(m_browserFontPanel, SIGNAL(toggled(bool)), this, SLOT(browserFontSettingToggled(bool))); + + QList<QComboBox*> allCombos = qFindChildren<QComboBox*>(m_appFontPanel); + foreach (QComboBox* box, allCombos) + connect(box, SIGNAL(currentIndexChanged(int)), this, SLOT(appFontSettingChanged(int))); + + allCombos.clear(); + allCombos = qFindChildren<QComboBox*>(m_browserFontPanel); + foreach (QComboBox* box, allCombos) + connect(box, SIGNAL(currentIndexChanged(int)), this, SLOT(browserFontSettingChanged(int))); +} + +void PreferencesDialog::appFontSettingToggled(bool on) +{ + Q_UNUSED(on) + m_appFontChanged = true; +} + +void PreferencesDialog::appFontSettingChanged(int index) +{ + Q_UNUSED(index) + m_appFontChanged = true; +} + +void PreferencesDialog::browserFontSettingToggled(bool on) +{ + Q_UNUSED(on) + m_browserFontChanged = true; +} + +void PreferencesDialog::browserFontSettingChanged(int index) +{ + Q_UNUSED(index) + m_browserFontChanged = true; +} + +void PreferencesDialog::updateOptionsPage() +{ + QString homepage = m_helpEngine->customValue(QLatin1String("homepage"), + QLatin1String("")).toString(); + + if (homepage.isEmpty()) { + homepage = m_helpEngine->customValue(QLatin1String("defaultHomepage"), + QLatin1String("help")).toString(); + } + + m_ui.homePageLineEdit->setText(homepage); + connect(m_ui.currentPageButton, SIGNAL(pressed()), this, + SLOT(currentHomepageChanged())); + connect(m_ui.restoreDefaultHomePageButton, SIGNAL(pressed()), this, + SLOT(restoreDefaultHomepage())); +} + +void PreferencesDialog::restoreDefaultHomepage() +{ + QString homepage = m_helpEngine->customValue( + QLatin1String("defaultHomepage"), QLatin1String("help")).toString(); + m_ui.homePageLineEdit->setText(homepage); +} + +void PreferencesDialog::currentHomepageChanged() +{ + QString homepage = CentralWidget::instance()->currentSource().toString(); + if (homepage.isEmpty()) + homepage = QLatin1String("help"); + + m_ui.homePageLineEdit->setText(homepage); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/preferencesdialog.h b/tools/assistant/tools/assistant/preferencesdialog.h new file mode 100644 index 0000000..a890500 --- /dev/null +++ b/tools/assistant/tools/assistant/preferencesdialog.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PREFERENCESDIALOG_H +#define PREFERENCESDIALOG_H + +#include <QtGui/QDialog> +#include "ui_preferencesdialog.h" + +QT_BEGIN_NAMESPACE + +class FontPanel; +class QHelpEngineCore; + +class PreferencesDialog : public QDialog +{ + Q_OBJECT + +public: + PreferencesDialog(QHelpEngineCore *helpEngine, QWidget *parent = 0); + ~PreferencesDialog(); + + void showDialog(); + +private slots: + void updateAttributes(QListWidgetItem *item); + void updateFilterMap(); + void addFilter(); + void removeFilter(); + void addDocumentationLocal(); + void removeDocumentation(); + void applyChanges(); + void appFontSettingToggled(bool on); + void appFontSettingChanged(int index); + void browserFontSettingToggled(bool on); + void browserFontSettingChanged(int index); + void restoreDefaultHomepage(); + void currentHomepageChanged(); + +signals: + void updateBrowserFont(); + void updateApplicationFont(); + +private: + void updateFilterPage(); + void updateFontSettingsPage(); + void updateOptionsPage(); + + Ui::PreferencesDialogClass m_ui; + QHelpEngineCore *m_helpEngine; + bool m_hideFiltersTab; + bool m_hideDocsTab; + QMap<QString, QStringList> m_filterMapBackup; + QMap<QString, QStringList> m_filterMap; + QStringList m_removedFilters; + QStringList m_docsBackup; + QStringList m_regDocs; + QStringList m_unregDocs; + QList<int> m_TabsToClose; + FontPanel *m_appFontPanel; + FontPanel *m_browserFontPanel; + bool m_appFontChanged; + bool m_browserFontChanged; +}; + +QT_END_NAMESPACE + +#endif // SETTINGSDIALOG_H diff --git a/tools/assistant/tools/assistant/preferencesdialog.ui b/tools/assistant/tools/assistant/preferencesdialog.ui new file mode 100644 index 0000000..d848b49 --- /dev/null +++ b/tools/assistant/tools/assistant/preferencesdialog.ui @@ -0,0 +1,310 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>PreferencesDialogClass</class> + <widget class="QDialog" name="PreferencesDialogClass"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>359</width> + <height>266</height> + </rect> + </property> + <property name="windowTitle"> + <string>Preferences</string> + </property> + <layout class="QVBoxLayout"> + <item> + <widget class="QTabWidget" name="tabWidget"> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="fontsTab"> + <attribute name="title"> + <string>Fonts</string> + </attribute> + <layout class="QGridLayout"> + <item row="0" column="0"> + <layout class="QHBoxLayout"> + <item> + <widget class="QLabel" name="fontLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Font settings:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="comboBox"> + <item> + <property name="text"> + <string>Browser</string> + </property> + </item> + <item> + <property name="text"> + <string>Application</string> + </property> + </item> + </widget> + </item> + </layout> + </item> + <item row="1" column="0"> + <widget class="QStackedWidget" name="stackedWidget_2"> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="page_4"/> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="filtersTab"> + <attribute name="title"> + <string>Filters</string> + </attribute> + <layout class="QGridLayout"> + <item row="0" column="0" colspan="2"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Filter:</string> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="label_2"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="text"> + <string>Attributes:</string> + </property> + </widget> + </item> + <item row="1" column="0" colspan="2"> + <widget class="QListWidget" name="filterWidget"/> + </item> + <item row="1" column="2" rowspan="2"> + <widget class="QTreeWidget" name="attributeWidget"> + <column> + <property name="text"> + <string>1</string> + </property> + </column> + </widget> + </item> + <item row="2" column="0"> + <widget class="QPushButton" name="filterAddButton"> + <property name="text"> + <string>Add</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QPushButton" name="filterRemoveButton"> + <property name="text"> + <string>Remove</string> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="docsTab"> + <attribute name="title"> + <string>Documentation</string> + </attribute> + <layout class="QVBoxLayout"> + <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Registered Documentation:</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout"> + <property name="spacing"> + <number>6</number> + </property> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QListWidget" name="registeredDocsListWidget"> + <property name="selectionMode"> + <enum>QAbstractItemView::ExtendedSelection</enum> + </property> + </widget> + </item> + <item> + <layout class="QVBoxLayout"> + <property name="spacing"> + <number>6</number> + </property> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QPushButton" name="docAddButton"> + <property name="text"> + <string>Add...</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="docRemoveButton"> + <property name="text"> + <string>Remove</string> + </property> + </widget> + </item> + <item> + <spacer> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </item> + </layout> + </widget> + <widget class="QWidget" name="optionsTab"> + <attribute name="title"> + <string>Options</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Homepage</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QLineEdit" name="homePageLineEdit"/> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <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> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QPushButton" name="currentPageButton"> + <property name="text"> + <string>Current Page</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="restoreDefaultHomePageButton"> + <property name="text"> + <string>Restore to default</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>72</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </widget> + </item> + <item> + <layout class="QHBoxLayout"> + <property name="spacing"> + <number>6</number> + </property> + <property name="margin"> + <number>0</number> + </property> + <item> + <spacer> + <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="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <layoutdefault spacing="6" margin="11"/> + <resources/> + <connections> + <connection> + <sender>comboBox</sender> + <signal>currentIndexChanged(int)</signal> + <receiver>stackedWidget_2</receiver> + <slot>setCurrentIndex(int)</slot> + <hints> + <hint type="sourcelabel"> + <x>375</x> + <y>32</y> + </hint> + <hint type="destinationlabel"> + <x>347</x> + <y>125</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/tools/assistant/tools/assistant/qtdocinstaller.cpp b/tools/assistant/tools/assistant/qtdocinstaller.cpp new file mode 100644 index 0000000..9063847 --- /dev/null +++ b/tools/assistant/tools/assistant/qtdocinstaller.cpp @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QDir> +#include <QtCore/QLibraryInfo> +#include <QtCore/QDateTime> +#include <QtHelp/QHelpEngineCore> +#include "qtdocinstaller.h" + +QT_BEGIN_NAMESPACE + +QtDocInstaller::QtDocInstaller(const QString &collectionFile) +{ + m_abort = false; + m_collectionFile = collectionFile; +} + +QtDocInstaller::~QtDocInstaller() +{ + if (!isRunning()) + return; + m_mutex.lock(); + m_abort = true; + m_mutex.unlock(); + wait(); +} + +void QtDocInstaller::installDocs() +{ + 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"); + + foreach (const QString &doc, docs) { + changes |= installDoc(doc, helpEngine); + 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) +{ + 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("|")); + + QDateTime dt; + if (lst.count() && !lst.first().isEmpty()) + dt = QDateTime::fromString(lst.first(), Qt::ISODate); + + QString qchFile; + if (lst.count() == 2) + qchFile = lst.last(); + + QDir dir(QLibraryInfo::location(QLibraryInfo::DocumentationPath) + + QDir::separator() + QLatin1String("qch")); + + const QStringList files = dir.entryList(QStringList() << QLatin1String("*.qch")); + if (files.isEmpty()) { + helpEngine->setCustomValue(versionKey, QDateTime().toString(Qt::ISODate) + + QLatin1String("|")); + 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) + && 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()); + return true; + } + } + return false; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/qtdocinstaller.h b/tools/assistant/tools/assistant/qtdocinstaller.h new file mode 100644 index 0000000..a8a98fa --- /dev/null +++ b/tools/assistant/tools/assistant/qtdocinstaller.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTDOCINSTALLER +#define QTDOCINSTALLER + +#include <QtCore/QThread> +#include <QtCore/QMutex> + +QT_BEGIN_NAMESPACE + +class QHelpEngineCore; + +class QtDocInstaller : public QThread +{ + Q_OBJECT + +public: + QtDocInstaller(const QString &collectionFile); + ~QtDocInstaller(); + void installDocs(); + +signals: + void errorMessage(const QString &msg); + void docsInstalled(bool newDocsInstalled); + +private: + void run(); + bool installDoc(const QString &name, + QHelpEngineCore *helpEngine); + + bool m_abort; + QString m_collectionFile; + QMutex m_mutex; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/tools/assistant/remotecontrol.cpp b/tools/assistant/tools/assistant/remotecontrol.cpp new file mode 100644 index 0000000..f374538 --- /dev/null +++ b/tools/assistant/tools/assistant/remotecontrol.cpp @@ -0,0 +1,283 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "remotecontrol.h" +#include "mainwindow.h" +#include "centralwidget.h" + +#include <QtCore/QFile> +#include <QtCore/QThread> +#include <QtCore/QTextStream> +#include <QtCore/QSocketNotifier> + +#include <QtGui/QMessageBox> +#include <QtGui/QApplication> + +#include <QtHelp/QHelpEngine> +#include <QtHelp/QHelpIndexWidget> + +#ifdef Q_OS_WIN +# include "remotecontrol_win.h" +#endif + +QT_BEGIN_NAMESPACE + +#ifdef Q_OS_WIN + +StdInListenerWin::StdInListenerWin(QObject *parent) + : QThread(parent) +{ +} + +StdInListenerWin::~StdInListenerWin() +{ + terminate(); + wait(); +} + +void StdInListenerWin::run() +{ + bool ok = true; + char chBuf[4096]; + DWORD dwRead; + HANDLE hStdin, hStdinDup; + + hStdin = GetStdHandle(STD_INPUT_HANDLE); + if (hStdin == INVALID_HANDLE_VALUE) + return; + + DuplicateHandle(GetCurrentProcess(), hStdin, + GetCurrentProcess(), &hStdinDup, + 0, false, DUPLICATE_SAME_ACCESS); + + CloseHandle(hStdin); + + while (ok) { + ok = ReadFile(hStdinDup, chBuf, 4096, &dwRead, NULL); + if (ok && dwRead != 0) + emit receivedCommand(QString::fromLocal8Bit(chBuf)); + } +} +#endif + +RemoteControl::RemoteControl(MainWindow *mainWindow, QHelpEngine *helpEngine) + : QObject(mainWindow) + , m_mainWindow(mainWindow) + , m_helpEngine(helpEngine) + , m_debug(false) + , m_caching(true) + , m_syncContents(false) + , m_expandTOC(-3) + +{ + connect(m_mainWindow, SIGNAL(initDone()), this, SLOT(applyCache())); +#ifdef Q_OS_WIN + StdInListenerWin *l = new StdInListenerWin(this); + connect(l, SIGNAL(receivedCommand(const QString&)), + this, SLOT(handleCommandString(const QString&))); + l->start(); +#else + QSocketNotifier *notifier = new QSocketNotifier(fileno(stdin), + QSocketNotifier::Read, this); + connect(notifier, SIGNAL(activated(int)), this, SLOT(receivedData())); + notifier->setEnabled(true); +#endif +} + +void RemoteControl::receivedData() +{ + QByteArray ba; + while (true) { + char c = getc(stdin); + if (c == EOF || c == '\0') + break; + if (c) + ba.append(c); + if (c == '\n') + break; + } + handleCommandString(QString::fromLocal8Bit(ba)); +} + +void RemoteControl::handleCommandString(const QString &cmdString) +{ + 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(); + + 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_caching) { + clearCache(); + m_currentFilter = arg; + } else { + m_helpEngine->setCurrentFilter(arg); + } + } else { + return; + } + ++it; + } + m_mainWindow->raise(); + m_mainWindow->activateWindow(); +} + +void RemoteControl::applyCache() +{ + if (m_setSource.isValid()) { + CentralWidget::instance()->setSource(m_setSource); + } else if (!m_activateKeyword.isEmpty()) { + m_mainWindow->setIndexString(m_activateKeyword); + m_helpEngine->indexWidget()->activateCurrentItem(); + } else if (!m_activateIdentifier.isEmpty()) { + QMap<QString, QUrl> links = + m_helpEngine->linksForIdentifier(m_activateIdentifier); + if (links.count()) + CentralWidget::instance()->setSource(links.constBegin().value()); + } else if (!m_currentFilter.isEmpty()) { + m_helpEngine->setCurrentFilter(m_currentFilter); + } + + if (m_syncContents) + m_mainWindow->syncContents(); + + if (m_expandTOC != -3) + m_mainWindow->expandTOC(m_expandTOC); + + m_caching = false; +} + +void RemoteControl::clearCache() +{ + m_currentFilter.clear(); + m_setSource.clear(); + m_syncContents = false; + m_activateKeyword.clear(); + m_activateIdentifier.clear(); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/remotecontrol.h b/tools/assistant/tools/assistant/remotecontrol.h new file mode 100644 index 0000000..3c7c6c5 --- /dev/null +++ b/tools/assistant/tools/assistant/remotecontrol.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef REMOTECONTROL_H +#define REMOTECONTROL_H + +#include <QtCore/QObject> +#include <QtCore/QUrl> + +QT_BEGIN_NAMESPACE + +class MainWindow; +class QHelpEngine; + +class RemoteControl : public QObject +{ + Q_OBJECT + +public: + RemoteControl(MainWindow *mainWindow, QHelpEngine *helpEngine); + +private slots: + void receivedData(); + void handleCommandString(const QString &cmdString); + void applyCache(); + +private: + void clearCache(); + +private: + MainWindow *m_mainWindow; + QHelpEngine *m_helpEngine; + bool m_debug; + + bool m_caching; + QUrl m_setSource; + bool m_syncContents; + QString m_activateKeyword; + QString m_activateIdentifier; + int m_expandTOC; + QString m_currentFilter; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/tools/assistant/remotecontrol_win.h b/tools/assistant/tools/assistant/remotecontrol_win.h new file mode 100644 index 0000000..081eb25 --- /dev/null +++ b/tools/assistant/tools/assistant/remotecontrol_win.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef REMOTECONTROL_WIN_H +#define REMOTECONTROL_WIN_H + +#include <windows.h> +#include <QtCore/QThread> + +QT_BEGIN_NAMESPACE + +class StdInListenerWin : public QThread +{ + Q_OBJECT + +public: + StdInListenerWin(QObject *parent); + ~StdInListenerWin(); + +signals: + void receivedCommand(const QString &cmd); + +private: + void run(); + bool ok; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/tools/assistant/searchwidget.cpp b/tools/assistant/tools/assistant/searchwidget.cpp new file mode 100644 index 0000000..000c73d --- /dev/null +++ b/tools/assistant/tools/assistant/searchwidget.cpp @@ -0,0 +1,246 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mainwindow.h" +#include "searchwidget.h" + +#include <QtCore/QMap> +#include <QtCore/QString> +#include <QtCore/QStringList> + +#include <QtGui/QMenu> +#include <QtGui/QLayout> +#include <QtGui/QKeyEvent> +#include <QtGui/QClipboard> +#include <QtGui/QApplication> +#include <QtGui/QTextBrowser> + +#include <QtHelp/QHelpSearchEngine> +#include <QtHelp/QHelpSearchQueryWidget> +#include <QtHelp/QHelpSearchResultWidget> + +QT_BEGIN_NAMESPACE + +SearchWidget::SearchWidget(QHelpSearchEngine *engine, QWidget *parent) + : QWidget(parent) + , zoomCount(0) + , searchEngine(engine) +{ + QVBoxLayout *vLayout = new QVBoxLayout(this); + + resultWidget = searchEngine->resultWidget(); + QHelpSearchQueryWidget *queryWidget = searchEngine->queryWidget(); + + vLayout->addWidget(queryWidget); + vLayout->addWidget(resultWidget); + + setFocusProxy(queryWidget); + + connect(queryWidget, SIGNAL(search()), this, SLOT(search())); + connect(resultWidget, SIGNAL(requestShowLink(const QUrl&)), + this, SIGNAL(requestShowLink(const QUrl&))); + + connect(searchEngine, SIGNAL(searchingStarted()), this, SLOT(searchingStarted())); + connect(searchEngine, SIGNAL(searchingFinished(int)), this, SLOT(searchingFinished(int))); + + QTextBrowser* browser = qFindChild<QTextBrowser*>(resultWidget); + browser->viewport()->installEventFilter(this); +} + +SearchWidget::~SearchWidget() +{ + // nothing todo +} + +void SearchWidget::zoomIn() +{ +#ifndef QT_CLUCENE_SUPPORT + return; +#endif + + QTextBrowser* browser = qFindChild<QTextBrowser*>(resultWidget); + if (browser && zoomCount != 10) { + zoomCount++; + browser->zoomIn(); + } +} + +void SearchWidget::zoomOut() +{ +#ifndef QT_CLUCENE_SUPPORT + return; +#endif + + QTextBrowser* browser = qFindChild<QTextBrowser*>(resultWidget); + if (browser && zoomCount != -5) { + zoomCount--; + browser->zoomOut(); + } +} + +void SearchWidget::resetZoom() +{ +#ifndef QT_CLUCENE_SUPPORT + return; +#endif + + if (zoomCount == 0) + return; + + QTextBrowser* browser = qFindChild<QTextBrowser*>(resultWidget); + if (browser) { + browser->zoomOut(zoomCount); + zoomCount = 0; + } +} + +void SearchWidget::search() const +{ + QList<QHelpSearchQuery> query = searchEngine->queryWidget()->query(); + searchEngine->search(query); +} + +void SearchWidget::searchingStarted() +{ + qApp->setOverrideCursor(QCursor(Qt::WaitCursor)); +} + +void SearchWidget::searchingFinished(int hits) +{ + Q_UNUSED(hits) + qApp->restoreOverrideCursor(); +} + +bool SearchWidget::eventFilter(QObject* o, QEvent *e) +{ + QTextBrowser* browser = qFindChild<QTextBrowser*>(resultWidget); + if (browser && o == browser->viewport() && e->type() == QEvent::MouseButtonRelease){ + QMouseEvent *me = static_cast<QMouseEvent*>(e); + QUrl link = resultWidget->linkAt(me->pos()); + if (!link.isEmpty() || link.isValid()) { + bool controlPressed = me->modifiers() & Qt::ControlModifier; + if((me->button() == Qt::LeftButton && controlPressed) + || (me->button() == Qt::MidButton)) { + emit requestShowLinkInNewTab(link); + } + } + } + return QWidget::eventFilter(o,e); +} + +void SearchWidget::keyPressEvent(QKeyEvent *keyEvent) +{ + if (keyEvent->key() == Qt::Key_Escape) + MainWindow::activateCurrentBrowser(); + else + keyEvent->ignore(); +} + +void SearchWidget::contextMenuEvent(QContextMenuEvent *contextMenuEvent) +{ + QMenu menu; + QPoint point = contextMenuEvent->globalPos(); + +#ifdef QT_CLUCENE_SUPPORT + QTextBrowser* browser = qFindChild<QTextBrowser*>(resultWidget); + if (!browser) + return; + + point = browser->mapFromGlobal(point); + if (!browser->rect().contains(point, true)) + return; + + QUrl link = browser->anchorAt(point); + + QAction *copyAction = menu.addAction(tr("&Copy") + + QString(QLatin1String("\t") + QString(QKeySequence(Qt::CTRL | Qt::Key_C)))); + copyAction->setEnabled(QTextCursor(browser->textCursor()).hasSelection()); + + QAction *copyAnchorAction = menu.addAction(tr("Copy &Link Location")); + copyAnchorAction->setEnabled(!link.isEmpty() && link.isValid()); + + QAction *newTabAction = menu.addAction(tr("Open Link in New Tab") + + QString(QLatin1String("\t") + QString(QKeySequence(Qt::CTRL))) + + QLatin1String("LMB")); + newTabAction->setEnabled(!link.isEmpty() && link.isValid()); + + menu.addSeparator(); + + QAction *selectAllAction = menu.addAction(tr("Select All") + + QString(QLatin1String("\t") + QString(QKeySequence(Qt::CTRL | Qt::Key_A)))); + + QAction *usedAction = menu.exec(mapToGlobal(contextMenuEvent->pos())); + if (usedAction == copyAction) { + QTextCursor cursor = browser->textCursor(); + if (!cursor.isNull() && cursor.hasSelection()) { + QString selectedText = cursor.selectedText(); + QMimeData *data = new QMimeData(); + data->setText(selectedText); + QApplication::clipboard()->setMimeData(data); + } + } + else if (usedAction == copyAnchorAction) { + QApplication::clipboard()->setText(link.toString()); + } + else if (usedAction == newTabAction) { + emit requestShowLinkInNewTab(link); + } + else if (usedAction == selectAllAction) { + browser->selectAll(); + } +#else + point = resultWidget->mapFromGlobal(point); + QUrl link = resultWidget->linkAt(point); + if (link.isEmpty() || !link.isValid()) + return; + + QAction *curTab = menu.addAction(tr("Open Link")); + QAction *newTab = menu.addAction(tr("Open Link in New Tab")); + + QAction *action = menu.exec(mapToGlobal(contextMenuEvent->pos())); + if (curTab == action) + emit requestShowLink(link); + else if (newTab == action) + emit requestShowLinkInNewTab(link); +#endif +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/searchwidget.h b/tools/assistant/tools/assistant/searchwidget.h new file mode 100644 index 0000000..22fe80d --- /dev/null +++ b/tools/assistant/tools/assistant/searchwidget.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SEARCHWIDGET_H +#define SEARCHWIDGET_H + +#include <QtCore/QUrl> +#include <QtCore/QPoint> + +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE + +class QMouseEvent; +class QHelpSearchEngine; +class QHelpSearchResultWidget; + +class SearchWidget : public QWidget +{ + Q_OBJECT + +public: + SearchWidget(QHelpSearchEngine *engine, QWidget *parent = 0); + ~SearchWidget(); + + void zoomIn(); + void zoomOut(); + void resetZoom(); + +signals: + void requestShowLink(const QUrl &url); + void requestShowLinkInNewTab(const QUrl &url); + +private slots: + void search() const; + void searchingStarted(); + void searchingFinished(int hits); + +private: + bool eventFilter(QObject* o, QEvent *e); + void keyPressEvent(QKeyEvent *keyEvent); + void contextMenuEvent(QContextMenuEvent *contextMenuEvent); + +private: + int zoomCount; + QHelpSearchEngine *searchEngine; + QHelpSearchResultWidget *resultWidget; +}; + +QT_END_NAMESPACE + +#endif // SEARCHWIDGET_H diff --git a/tools/assistant/tools/assistant/topicchooser.cpp b/tools/assistant/tools/assistant/topicchooser.cpp new file mode 100644 index 0000000..3f30417 --- /dev/null +++ b/tools/assistant/tools/assistant/topicchooser.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QMap> +#include <QtCore/QUrl> + +#include "topicchooser.h" + +QT_BEGIN_NAMESPACE + +TopicChooser::TopicChooser(QWidget *parent, const QString &keyword, + const QMap<QString, QUrl> &links) + : QDialog(parent) +{ + 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) + ui.listWidget->addItem(it.key()); + + 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())); +} + +QUrl TopicChooser::link() const +{ + QListWidgetItem *item = ui.listWidget->currentItem(); + if (!item) + return QUrl(); + + QString title = item->text(); + if (title.isEmpty() || !m_links.contains(title)) + return QUrl(); + + return m_links.value(title); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/topicchooser.h b/tools/assistant/tools/assistant/topicchooser.h new file mode 100644 index 0000000..58b3796 --- /dev/null +++ b/tools/assistant/tools/assistant/topicchooser.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TOPICCHOOSER_H +#define TOPICCHOOSER_H + +#include "ui_topicchooser.h" + +#include <QUrl> +#include <QMap> +#include <QString> + +#include <QtGui/QDialog> + +QT_BEGIN_NAMESPACE + +class TopicChooser : public QDialog +{ + Q_OBJECT + +public: + TopicChooser(QWidget *parent, const QString &keyword, + const QMap<QString, QUrl> &links); + + QUrl link() const; + +private: + Ui::TopicChooser ui; + QMap<QString, QUrl> m_links; +}; + +QT_END_NAMESPACE + +#endif // TOPICCHOOSER_H diff --git a/tools/assistant/tools/assistant/topicchooser.ui b/tools/assistant/tools/assistant/topicchooser.ui new file mode 100644 index 0000000..d4c90bb --- /dev/null +++ b/tools/assistant/tools/assistant/topicchooser.ui @@ -0,0 +1,116 @@ +<UI version="4.0" stdsetdef="1" > + <class>TopicChooser</class> + <widget class="QDialog" name="TopicChooser" > + <property name="objectName" > + <string notr="true">TopicChooser</string> + </property> + <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="sizeGripEnabled" > + <bool>true</bool> + </property> + <layout class="QVBoxLayout" > + <property name="objectName" > + <string notr="true">unnamed</string> + </property> + <property name="margin" > + <number>11</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QLabel" name="label" > + <property name="objectName" > + <string notr="true">label</string> + </property> + <property name="text" > + <string>&Topics</string> + </property> + <property name="buddy" stdset="0" > + <cstring>listWidget</cstring> + </property> + </widget> + </item> + <item> + <widget class="QListWidget" name="listWidget" > + <property name="objectName" > + <string notr="true">listWidget</string> + </property> + </widget> + </item> + <item> + <widget class="QWidget" name="Layout16" > + <property name="objectName" > + <string notr="true">Layout16</string> + </property> + <layout class="QHBoxLayout" > + <property name="objectName" > + <string notr="true">unnamed</string> + </property> + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <spacer name="Horizontal Spacing2" > + <property name="sizeHint" > + <size> + <width>20</width> + <height>20</height> + </size> + </property> + <property name="sizeType" > + <enum>Expanding</enum> + </property> + <property name="orientation" > + <enum>Horizontal</enum> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="buttonDisplay" > + <property name="objectName" > + <string notr="true">buttonDisplay</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="objectName" > + <string notr="true">buttonCancel</string> + </property> + <property name="text" > + <string>&Close</string> + </property> + <property name="autoDefault" > + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> +</UI> diff --git a/tools/assistant/tools/qcollectiongenerator/main.cpp b/tools/assistant/tools/qcollectiongenerator/main.cpp new file mode 100644 index 0000000..68db53f --- /dev/null +++ b/tools/assistant/tools/qcollectiongenerator/main.cpp @@ -0,0 +1,559 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../shared/helpgenerator.h" + +#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 +{ +public: + void readData(const QByteArray &contents); + + QString title() const { return m_title; } + QString homePage() const { return m_homePage; } + QString startPage() const { return m_startPage; } + QString applicationIcon() const { return m_applicationIcon; } + QString currentFilter() const { return m_currentFilter; } + bool enableFilterFunctionality() const + { return m_enableFilterFunctionality; } + bool hideFilterFunctionality() const + { return m_hideFilterFunctionality; } + bool enableAddressBar() const { return m_enableAddressBar; } + bool hideAddressBar() const { return m_hideAddressBar; } + bool enableDocumentationManager() const + { return m_enableDocumentationManager; } + + QMap<QString, QString> aboutMenuTexts() const + { return m_aboutMenuTexts; } + QString aboutIcon() const { return m_aboutIcon; } + QMap<QString, QString> aboutTextFiles() const + { return m_aboutTextFiles; } + + QMap<QString, QString> filesToGenerate() const + { return m_filesToGenerate; } + + QStringList filesToRegister() const { return m_filesToRegister; } + + QString cacheDirectory() const { return m_cacheDirectory; } + +private: + void raiseErrorWithLine(); + void readConfig(); + void readAssistantSettings(); + void readMenuTexts(); + void readAboutDialog(); + void readDocFiles(); + void readGenerate(); + void readFiles(); + void readRegister(); + + QString m_title; + QString m_homePage; + QString m_startPage; + QString m_applicationIcon; + QString m_currentFilter; + bool m_enableFilterFunctionality; + bool m_hideFilterFunctionality; + bool m_enableAddressBar; + bool m_hideAddressBar; + bool m_enableDocumentationManager; + QMap<QString, QString> m_aboutMenuTexts; + QString m_aboutIcon; + QMap<QString, QString> m_aboutTextFiles; + QMap<QString, QString> m_filesToGenerate; + QStringList m_filesToRegister; + QString m_cacheDirectory; +}; + +void CollectionConfigReader::raiseErrorWithLine() +{ + raiseError(QObject::tr("Unknown token at line %1.") + .arg(lineNumber())); +} + +void CollectionConfigReader::readData(const QByteArray &contents) +{ + m_enableFilterFunctionality = true; + m_hideFilterFunctionality = true; + m_enableAddressBar = true; + m_hideAddressBar = true; + m_enableDocumentationManager = true; + + addData(contents); + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("QHelpCollectionProject") + && attributes().value(QLatin1String("version")) == QLatin1String("1.0")) + readConfig(); + else + raiseError(QObject::tr("Unknown token at line %1. Expected \"QtHelpCollectionProject\"!") + .arg(lineNumber())); + } + } +} + +void CollectionConfigReader::readConfig() +{ + bool ok = false; + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("assistant")) + readAssistantSettings(); + else if (name() == QLatin1String("docFiles")) + readDocFiles(); + else + raiseErrorWithLine(); + } else if (isEndElement() && name() == QLatin1String("QHelpCollectionProject")) { + ok = true; + } + } + if (!ok && !hasError()) + raiseError(QLatin1String("Missing end tags.")); +} + +void CollectionConfigReader::readAssistantSettings() +{ + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("title")) { + m_title = readElementText(); + } else if (name() == QLatin1String("homePage")) { + m_homePage = readElementText(); + } else if (name() == QLatin1String("startPage")) { + m_startPage = readElementText(); + } else if (name() == QLatin1String("currentFilter")) { + m_currentFilter = readElementText(); + } else if (name() == QLatin1String("applicationIcon")) { + m_applicationIcon = readElementText(); + } else if (name() == QLatin1String("enableFilterFunctionality")) { + if (attributes().value(QLatin1String("visible")) == QLatin1String("true")) + m_hideFilterFunctionality = false; + if (readElementText() == QLatin1String("false")) + m_enableFilterFunctionality = false; + } else if (name() == QLatin1String("enableDocumentationManager")) { + if (readElementText() == QLatin1String("false")) + m_enableDocumentationManager = false; + } else if (name() == QLatin1String("enableAddressBar")) { + if (attributes().value(QLatin1String("visible")) == QLatin1String("true")) + m_hideAddressBar = false; + if (readElementText() == QLatin1String("false")) + m_enableAddressBar = false; + } else if (name() == QLatin1String("aboutMenuText")) { + readMenuTexts(); + } else if (name() == QLatin1String("aboutDialog")) { + readAboutDialog(); + } else if (name() == "cacheDirectory") { + m_cacheDirectory = readElementText(); + } else { + raiseErrorWithLine(); + } + } else if (isEndElement() && name() == QLatin1String("assistant")) { + break; + } + } +} + +void CollectionConfigReader::readMenuTexts() +{ + while (!atEnd()) + { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("text")) { + QString lang = attributes().value(QLatin1String("language")).toString(); + if (lang.isEmpty()) + lang = QLatin1String("default"); + m_aboutMenuTexts.insert(lang, readElementText()); + } else { + raiseErrorWithLine(); + } + } else if (isEndElement() && name() == QLatin1String("aboutMenuText")) { + break; + } + } +} + +void CollectionConfigReader::readAboutDialog() +{ + while (!atEnd()) + { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("file")) { + QString lang = attributes().value(QLatin1String("language")).toString(); + if (lang.isEmpty()) + lang = QLatin1String("default"); + m_aboutTextFiles.insert(lang, readElementText()); + } else if (name() == QLatin1String("icon")) { + m_aboutIcon = readElementText(); + } else { + raiseErrorWithLine(); + } + } else if (isEndElement() && name() == QLatin1String("aboutDialog")) { + break; + } + } +} + +void CollectionConfigReader::readDocFiles() +{ + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("generate")) { + readGenerate(); + } else if (name() == QLatin1String("register")) { + readRegister(); + } else { + raiseErrorWithLine(); + } + } else if (isEndElement() && name() == QLatin1String("docFiles")) { + break; + } + } +} + +void CollectionConfigReader::readGenerate() +{ + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("file")) + readFiles(); + else + raiseErrorWithLine(); + } else if (isEndElement() && name() == QLatin1String("generate")) { + break; + } + } +} + +void CollectionConfigReader::readFiles() +{ + QString input; + QString output; + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("input")) + input = readElementText(); + else if (name() == QLatin1String("output")) + output = readElementText(); + else + raiseErrorWithLine(); + } else if (isEndElement() && name() == QLatin1String("file")) { + break; + } + } + if (input.isEmpty() || output.isEmpty()) { + raiseError(QLatin1String("Missing input or output file for help file generation!")); + return; + } + m_filesToGenerate.insert(input, output); +} + +void CollectionConfigReader::readRegister() +{ + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("file")) + m_filesToRegister.append(readElementText()); + else + raiseErrorWithLine(); + } else if (isEndElement() && name() == QLatin1String("register")) { + break; + } + } +} + +int main(int argc, char *argv[]) +{ + QString error; + QString arg; + QString collectionFile; + QString configFile; + QString basePath; + bool showHelp = false; + bool showVersion = false; + + for (int i=1; i<argc; ++i) { + arg = QString::fromLocal8Bit(argv[i]); + if (arg == QLatin1String("-o")) { + if (++i < argc) { + QFileInfo fi(QString::fromLocal8Bit(argv[i])); + collectionFile = fi.absoluteFilePath(); + } else { + error = QObject::tr("Missing output file name!"); + } + } else if (arg == QLatin1String("-h")) { + showHelp = true; + } else if (arg == QLatin1String("-v")) { + showVersion = true; + } else { + QFileInfo fi(arg); + configFile = fi.absoluteFilePath(); + basePath = fi.absolutePath(); + } + } + + if (showVersion) { + 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!"); + + QString help = QObject::tr("\nUsage:\n\n" + "qcollectiongenerator <collection-config-file> [options]\n\n" + " -o <collection-file> Generates a collection file\n" + " called <collection-file>. If\n" + " this option is not specified\n" + " a default name will be used.\n" + " -v Displays the version of\n" + " qcollectiongenerator.\n\n"); + + if (showHelp) { + fprintf(stdout, "%s", qPrintable(help)); + return 0; + }else if (!error.isEmpty()) { + fprintf(stderr, "%s\n\n%s", qPrintable(error), qPrintable(help)); + return -1; + } + + QFile file(configFile); + if (!file.open(QIODevice::ReadOnly)) { + fprintf(stderr, "Could not open %s!\n", qPrintable(configFile)); + return -1; + } + + if (collectionFile.isEmpty()) { + QFileInfo fi(configFile); + collectionFile = basePath + QDir::separator() + + fi.baseName() + QLatin1String(".qhc"); + } + + QCoreApplication app(argc, argv); + + fprintf(stdout, "Reading collection config file...\n"); + CollectionConfigReader config; + config.readData(file.readAll()); + if (config.hasError()) { + fprintf(stderr, "Collection config file error: %s\n", qPrintable(config.errorString())); + return -1; + } + + QMap<QString, QString>::const_iterator it = config.filesToGenerate().constBegin(); + 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())) { + fprintf(stderr, "%s\n", qPrintable(helpData.errorMessage())); + return -1; + } + + HelpGenerator helpGenerator; + if (!helpGenerator.generate(&helpData, basePath + QDir::separator() + it.value())) { + fprintf(stderr, "%s\n", qPrintable(helpGenerator.error())); + return -1; + } + ++it; + } + + fprintf(stdout, "Creating collection file...\n"); + + QFileInfo colFi(collectionFile); + if (colFi.exists()) { + if (!colFi.dir().remove(colFi.fileName())) { + fprintf(stderr, "The file %s cannot be overwritten!\n", qPrintable(collectionFile)); + return -1; + } + } + + QHelpEngineCore helpEngine(collectionFile); + if (!helpEngine.setupData()) { + fprintf(stderr, "%s\n", qPrintable(helpEngine.error())); + return -1; + } + + foreach (const QString &file, config.filesToRegister()) { + if (!helpEngine.registerDocumentation(basePath + QDir::separator() + file)) { + fprintf(stderr, "%s\n", qPrintable(helpEngine.error())); + return -1; + } + } + + if (!config.title().isEmpty()) + helpEngine.setCustomValue(QLatin1String("WindowTitle"), config.title()); + + if (!config.homePage().isEmpty()) { + helpEngine.setCustomValue(QLatin1String("defaultHomepage"), + config.homePage()); + } + + if (!config.startPage().isEmpty()) + helpEngine.setCustomValue(QLatin1String("LastShownPages"), config.startPage()); + + if (!config.currentFilter().isEmpty()) + helpEngine.setCustomValue(QLatin1String("CurrentFilter"), config.currentFilter()); + + if (!config.cacheDirectory().isEmpty()) + helpEngine.setCustomValue(QLatin1String("CacheDirectory"), config.cacheDirectory()); + + helpEngine.setCustomValue(QLatin1String("EnableFilterFunctionality"), + config.enableFilterFunctionality()); + helpEngine.setCustomValue(QLatin1String("HideFilterFunctionality"), + config.hideFilterFunctionality()); + helpEngine.setCustomValue(QLatin1String("EnableDocumentationManager"), + config.enableDocumentationManager()); + helpEngine.setCustomValue(QLatin1String("EnableAddressBar"), + config.enableAddressBar()); + helpEngine.setCustomValue(QLatin1String("HideAddressBar"), + config.hideAddressBar()); + helpEngine.setCustomValue(QLatin1String("CreationTime"), + QDateTime::currentDateTime().toTime_t()); + + if (!config.applicationIcon().isEmpty()) { + QFile icon(basePath + QDir::separator() + config.applicationIcon()); + if (!icon.open(QIODevice::ReadOnly)) { + fprintf(stderr, "Cannot open %s!\n", qPrintable(icon.fileName())); + return -1; + } + helpEngine.setCustomValue(QLatin1String("ApplicationIcon"), icon.readAll()); + } + + if (config.aboutMenuTexts().count()) { + QByteArray ba; + QDataStream s(&ba, QIODevice::WriteOnly); + QMap<QString, QString>::const_iterator it = config.aboutMenuTexts().constBegin(); + while (it != config.aboutMenuTexts().constEnd()) { + s << it.key(); + s << it.value(); + ++it; + } + helpEngine.setCustomValue(QLatin1String("AboutMenuTexts"), ba); + } + + if (!config.aboutIcon().isEmpty()) { + QFile icon(basePath + QDir::separator() + config.aboutIcon()); + if (!icon.open(QIODevice::ReadOnly)) { + fprintf(stderr, "Cannot open %s!\n", qPrintable(icon.fileName())); + return -1; + } + helpEngine.setCustomValue(QLatin1String("AboutIcon"), icon.readAll()); + } + + if (config.aboutTextFiles().count()) { + QByteArray ba; + QDataStream s(&ba, QIODevice::WriteOnly); + QMap<QString, QString>::const_iterator it = config.aboutTextFiles().constBegin(); + QMap<QString, QByteArray> imgData; + + QRegExp srcRegExp(QLatin1String("src=(\"(.+)\"|([^\"\\s]+)).*>")); + srcRegExp.setMinimal(true); + QRegExp imgRegExp(QLatin1String("(<img[^>]+>)")); + imgRegExp.setMinimal(true); + + while (it != config.aboutTextFiles().constEnd()) { + s << it.key(); + QFileInfo fi(basePath + QDir::separator() + it.value()); + QFile f(fi.absoluteFilePath()); + if (!f.open(QIODevice::ReadOnly)) { + fprintf(stderr, "Cannot open %s!\n", qPrintable(f.fileName())); + return -1; + } + QByteArray data = f.readAll(); + s << data; + + QString contents = QString::fromUtf8(data); + int pos = 0; + while ((pos = imgRegExp.indexIn(contents, pos)) != -1) { + QString imgTag = imgRegExp.cap(1); + pos += imgRegExp.matchedLength(); + + if (srcRegExp.indexIn(imgTag, 0) != -1) { + QString src = srcRegExp.cap(2); + if (src.isEmpty()) + src = srcRegExp.cap(3); + + QFile img(fi.absolutePath() + QDir::separator() + src); + if (img.open(QIODevice::ReadOnly)) { + if (!imgData.contains(src)) + imgData.insert(src, img.readAll()); + } else { + fprintf(stderr, "Cannot open referenced image file %s!\n", + qPrintable(img.fileName())); + } + } + } + ++it; + } + helpEngine.setCustomValue(QLatin1String("AboutTexts"), ba); + if (imgData.count()) { + QByteArray imageData; + QBuffer buffer(&imageData); + buffer.open(QIODevice::WriteOnly); + QDataStream out(&buffer); + out << imgData; + helpEngine.setCustomValue(QLatin1String("AboutImages"), imageData); + } + } + + return 0; +} diff --git a/tools/assistant/tools/qcollectiongenerator/qcollectiongenerator.pro b/tools/assistant/tools/qcollectiongenerator/qcollectiongenerator.pro new file mode 100644 index 0000000..cf70e48 --- /dev/null +++ b/tools/assistant/tools/qcollectiongenerator/qcollectiongenerator.pro @@ -0,0 +1,14 @@ +QT += xml network +TEMPLATE = app +DESTDIR = ../../../../bin +TARGET = qcollectiongenerator +CONFIG += qt warn_on help console +CONFIG -= app_bundle + +target.path=$$[QT_INSTALL_BINS] +INSTALLS += target + +SOURCES += ../shared/helpgenerator.cpp \ + main.cpp + +HEADERS += ../shared/helpgenerator.h diff --git a/tools/assistant/tools/qhelpconverter/adpreader.cpp b/tools/assistant/tools/qhelpconverter/adpreader.cpp new file mode 100644 index 0000000..930417a --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/adpreader.cpp @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "adpreader.h" + +QT_BEGIN_NAMESPACE + +void AdpReader::readData(const QByteArray &contents) +{ + clear(); + m_contents.clear(); + m_keywords.clear(); + m_properties.clear(); + m_files.clear(); + addData(contents); + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name().toString().toLower() == QLatin1String("assistantconfig") + && attributes().value(QLatin1String("version")) == QLatin1String("3.2.0")) { + readProject(); + } else if (name().toString().toLower() == QLatin1String("dcf")) { + QString ref = attributes().value(QLatin1String("ref")).toString(); + addFile(ref); + m_contents.append(ContentItem(attributes().value(QLatin1String("title")).toString(), + ref, 0)); + readDCF(); + } else { + raiseError(); + } + } + } +} + +QList<ContentItem> AdpReader::contents() const +{ + return m_contents; +} + +QList<KeywordItem> AdpReader::keywords() const +{ + return m_keywords; +} + +QSet<QString> AdpReader::files() const +{ + return m_files; +} + +QMap<QString, QString> AdpReader::properties() const +{ + return m_properties; +} + +void AdpReader::readProject() +{ + while (!atEnd()) { + readNext(); + if (isStartElement()) { + QString s = name().toString().toLower(); + if (s == QLatin1String("profile")) { + readProfile(); + } else if (s == QLatin1String("dcf")) { + QString ref = attributes().value(QLatin1String("ref")).toString(); + addFile(ref); + m_contents.append(ContentItem(attributes().value(QLatin1String("title")).toString(), + ref, 0)); + readDCF(); + } else { + raiseError(); + } + } + } +} + +void AdpReader::readProfile() +{ + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name().toString().toLower() == QLatin1String("property")) { + QString prop = attributes().value(QLatin1String("name")).toString().toLower(); + m_properties[prop] = readElementText(); + } else { + raiseError(); + } + } else if (isEndElement()) { + break; + } + } +} + +void AdpReader::readDCF() +{ + int depth = 0; + while (!atEnd()) { + readNext(); + QString str = name().toString().toLower(); + if (isStartElement()) { + if (str == QLatin1String("section")) { + QString ref = attributes().value(QLatin1String("ref")).toString(); + addFile(ref); + m_contents.append(ContentItem(attributes().value(QLatin1String("title")).toString(), + ref, ++depth)); + } else if (str == QLatin1String("keyword")) { + QString ref = attributes().value(QLatin1String("ref")).toString(); + addFile(ref); + m_keywords.append(KeywordItem(readElementText(), ref)); + } else { + raiseError(); + } + } else if (isEndElement()) { + if (str == QLatin1String("section")) + --depth; + else if (str == QLatin1String("dcf")) + break; + } + } +} + +void AdpReader::addFile(const QString &file) +{ + QString s = file; + if (s.startsWith(QLatin1String("./"))) + s = s.mid(2); + int i = s.indexOf(QLatin1Char('#')); + if (i > -1) + s = s.left(i); + if (!m_files.contains(s)) + m_files.insert(s); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/qhelpconverter/adpreader.h b/tools/assistant/tools/qhelpconverter/adpreader.h new file mode 100644 index 0000000..a7fa606 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/adpreader.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ADPREADER_H +#define ADPREADER_H + +#include <QtCore/QMap> +#include <QtCore/QSet> +#include <QtXml/QXmlStreamReader> + +QT_BEGIN_NAMESPACE + +struct ContentItem { + ContentItem(const QString &t, const QString &r, int d) + : title(t), reference(r), depth(d) {} + QString title; + QString reference; + int depth; +}; + +struct KeywordItem { + KeywordItem(const QString &k, const QString &r) + : keyword(k), reference(r) {} + QString keyword; + QString reference; +}; + +class AdpReader : public QXmlStreamReader +{ +public: + void readData(const QByteArray &contents); + QList<ContentItem> contents() const; + QList<KeywordItem> keywords() const; + QSet<QString> files() const; + + QMap<QString, QString> properties() const; + +private: + void readProject(); + void readProfile(); + void readDCF(); + void addFile(const QString &file); + + QMap<QString, QString> m_properties; + QList<ContentItem> m_contents; + QList<KeywordItem> m_keywords; + QSet<QString> m_files; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/tools/qhelpconverter/assistant-128.png b/tools/assistant/tools/qhelpconverter/assistant-128.png Binary files differnew file mode 100644 index 0000000..f05949f --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/assistant-128.png diff --git a/tools/assistant/tools/qhelpconverter/assistant.png b/tools/assistant/tools/qhelpconverter/assistant.png Binary files differnew file mode 100644 index 0000000..ea4d1e7 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/assistant.png diff --git a/tools/assistant/tools/qhelpconverter/conversionwizard.cpp b/tools/assistant/tools/qhelpconverter/conversionwizard.cpp new file mode 100644 index 0000000..c3fe94a0 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/conversionwizard.cpp @@ -0,0 +1,265 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QFileInfo> +#include <QtCore/QDir> +#include <QtCore/QVariant> +#include <QtCore/QTimer> +#include <QtGui/QApplication> +#include <QtGui/QMouseEvent> + +#include "conversionwizard.h" +#include "inputpage.h" +#include "generalpage.h" +#include "filterpage.h" +#include "identifierpage.h" +#include "pathpage.h" +#include "filespage.h" +#include "outputpage.h" +#include "finishpage.h" +#include "qhpwriter.h" +#include "qhcpwriter.h" +#include "helpwindow.h" + +QT_BEGIN_NAMESPACE + +ConversionWizard::ConversionWizard() +{ + setWindowIcon(QIcon(QLatin1String(":/trolltech/qhelpconverter/assistant.png"))); + setWindowTitle(tr("Help Conversion Wizard")); + setPixmap(QWizard::WatermarkPixmap, + QPixmap(QLatin1String(":/trolltech/qhelpconverter/assistant-128.png"))) ; + setOptions(QWizard::IndependentPages|QWizard::NoBackButtonOnLastPage + |QWizard::HaveHelpButton); + + m_inputPage = new InputPage(&m_adpReader); + setPage(Input_Page, m_inputPage); + + m_generalPage = new GeneralPage(); + setPage(General_Page, m_generalPage); + + m_filterPage = new FilterPage(); + setPage(Filter_Page, m_filterPage); + m_filterPage->setMaximumHeight(240); + + m_identifierPage = new IdentifierPage(); + setPage(Identifier_Page, m_identifierPage); + + m_pathPage = new PathPage(); + setPage(Path_Page, m_pathPage); + m_pathPage->setMaximumHeight(240); + + m_filesPage = new FilesPage(); + setPage(Files_Page, m_filesPage); + m_filesPage->setMaximumHeight(240); + + m_outputPage = new OutputPage(); + setPage(Output_Page, m_outputPage); + m_outputPage->setMaximumHeight(240); + + m_finishPage = new FinishPage(); + setPage(Finish_Page, m_finishPage); + m_finishPage->setMaximumHeight(240); + + connect(this, SIGNAL(currentIdChanged(int)), + this, SLOT(pageChanged(int))); + + m_helpWindow = 0; + qApp->installEventFilter(this); + + QAbstractButton *btn = button(QWizard::HelpButton); + btn->setCheckable(true); + connect(btn, SIGNAL(toggled(bool)), this, SLOT(showHelp(bool))); +} + +void ConversionWizard::setAdpFileName(const QString &fileName) +{ + setField(QLatin1String("adpFileName"), fileName); +} + +void ConversionWizard::initializePage(int id) +{ + switch (id) { + case Path_Page: { + QFileInfo fi(field(QLatin1String("adpFileName")).toString()); + m_pathPage->setPath(fi.absolutePath()); + break; + } + case Output_Page: { + QFileInfo fi(field(QLatin1String("adpFileName")).toString()); + m_outputPage->setPath(fi.absolutePath()); + setField(QLatin1String("ProjectFileName"), fi.baseName() + + QLatin1String(".qhp")); + setField(QLatin1String("CollectionFileName"), fi.baseName() + + QLatin1String(".qhcp")); + break; + } + } +} + +void ConversionWizard::pageChanged(int id) +{ + if (id == Files_Page) { + QApplication::setOverrideCursor(Qt::WaitCursor); + m_files.clear(); + QFileInfo fi(field(QLatin1String("adpFileName")).toString()); + QDir rootDir = fi.absolutePath(); + foreach (const QString &p, m_pathPage->paths()) { + QDir dir(p); + QString rel = rootDir.relativeFilePath(dir.absolutePath()); + if (!rel.isEmpty()) + rel.append(QLatin1Char('/')); + foreach (const QString &f, dir.entryList(m_pathPage->filters())) + m_files.append(rel + f); + } + m_filesPage->setFilesToRemove(getUnreferencedFiles(m_files)); + QApplication::restoreOverrideCursor(); + } else if (id == Output_Page) { + m_outputPage->setCollectionComponentEnabled( + !m_adpReader.properties().isEmpty()); + } else if (id == Finish_Page) { + QTimer::singleShot(300, this, SLOT(convert())); + } +} + +void ConversionWizard::showHelp(bool toggle) +{ + int w = 180; + int h = 180; + if (!m_helpWindow) { + m_helpWindow = new HelpWindow(this); + m_helpWindow->setMaximumWidth(w); + m_helpWindow->setMaximumHeight(h); + m_helpWindow->setMinimumHeight(h); + } + + if (toggle) { + m_helpWindow->setHelp(currentPage()->objectName()); + QAbstractButton *btn = button(QWizard::HelpButton); + QPoint p = btn->pos(); + int x = p.x(); + if (btn->pos().x() > w) + x = p.x() + btn->width() - w; + m_helpWindow->move(x, p.y()-h); + m_helpWindow->show(); + } else { + m_helpWindow->hide(); + } +} + +bool ConversionWizard::eventFilter(QObject *obj, QEvent *e) +{ + if (m_helpWindow && m_helpWindow->isVisible()) { + if (obj != button(QWizard::HelpButton) + && e->type() == QEvent::MouseButtonRelease) { + QMouseEvent *me = static_cast<QMouseEvent*>(e); + if (!m_helpWindow->geometry().contains(mapFromParent(me->globalPos()))) { + m_helpWindow->hide(); + button(QWizard::HelpButton)->setChecked(false); + } + } else if (e->type() == QEvent::KeyPress) { + m_helpWindow->hide(); + button(QWizard::HelpButton)->setChecked(false); + } + } + return QWizard::eventFilter(obj, e); +} + +QStringList ConversionWizard::getUnreferencedFiles(const QStringList &files) +{ + QStringList lst; + QSet<QString> adpFiles = m_adpReader.files(); + foreach (const QString &s, files) { + if (!adpFiles.contains(s)) + lst.append(s); + } + return lst; +} + +void ConversionWizard::convert() +{ + QFileInfo fi(field(QLatin1String("adpFileName")).toString()); + m_finishPage->appendMessage(tr("Converting %1...") + .arg(fi.fileName())); + QApplication::setOverrideCursor(Qt::WaitCursor); + QString qhpFileName = field(QLatin1String("ProjectFileName")).toString(); + QhpWriter qhpWriter(field(QLatin1String("namespaceName")).toString(), + field(QLatin1String("virtualFolder")).toString()); + qhpWriter.setAdpReader(&m_adpReader); + qhpWriter.setFilterAttributes(m_filterPage->filterAttributes()); + qhpWriter.setCustomFilters(m_filterPage->customFilters()); + + foreach (const QString &f, m_filesPage->filesToRemove()) + m_files.removeAll(f); + qhpWriter.setFiles(m_files); + + if (field(QLatin1String("createIdentifier")).toBool()) { + if (field(QLatin1String("fileNamePrefix")).toBool()) + qhpWriter.generateIdentifiers(QhpWriter::FilePrefix); + else + qhpWriter.generateIdentifiers(QhpWriter::GlobalPrefix, + field(QLatin1String("globalPrefix")).toString()); + } else { + qhpWriter.generateIdentifiers(QhpWriter::SkipAll); + } + + qhpWriter.writeFile(fi.absolutePath() + QDir::separator() + + qhpFileName); + + m_finishPage->appendMessage(tr("Writing help collection file...")); + + if (!m_adpReader.properties().isEmpty()) { + QhcpWriter qhcpWriter; + qhcpWriter.setHelpProjectFile(qhpFileName); + qhcpWriter.setProperties(m_adpReader.properties()); + qhcpWriter.setTitlePath(QLatin1String("qthelp://") + + field(QLatin1String("namespaceName")).toString() + + QLatin1String("/") + +field(QLatin1String("virtualFolder")).toString()); + qhcpWriter.writeFile(fi.absolutePath() + QDir::separator() + + field(QLatin1String("CollectionFileName")).toString()); + } + + m_finishPage->appendMessage(tr("Done.")); + QApplication::restoreOverrideCursor(); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/qhelpconverter/conversionwizard.h b/tools/assistant/tools/qhelpconverter/conversionwizard.h new file mode 100644 index 0000000..4c8fb02 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/conversionwizard.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CONVERSIONWIZARD_H +#define CONVERSIONWIZARD_H + +#include <QtGui/QWizard> +#include "adpreader.h" + +QT_BEGIN_NAMESPACE + +class InputPage; +class GeneralPage; +class FilterPage; +class IdentifierPage; +class PathPage; +class FilesPage; +class OutputPage; +class FinishPage; +class HelpWindow; + +class ConversionWizard : public QWizard +{ + Q_OBJECT + +public: + ConversionWizard(); + void setAdpFileName(const QString &fileName); + +private slots: + void pageChanged(int id); + void showHelp(bool toggle); + void convert(); + +private: + enum Pages {Input_Page, General_Page, Filter_Page, + Identifier_Page, Path_Page, Files_Page, Output_Page, + Finish_Page}; + void initializePage(int id); + QStringList getUnreferencedFiles(const QStringList &files); + bool eventFilter(QObject *obj, QEvent *e); + + AdpReader m_adpReader; + InputPage *m_inputPage; + GeneralPage *m_generalPage; + FilterPage *m_filterPage; + IdentifierPage *m_identifierPage; + PathPage *m_pathPage; + FilesPage *m_filesPage; + OutputPage *m_outputPage; + FinishPage *m_finishPage; + QStringList m_files; + HelpWindow *m_helpWindow; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/tools/qhelpconverter/doc/filespage.html b/tools/assistant/tools/qhelpconverter/doc/filespage.html new file mode 100644 index 0000000..a7aac18 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/doc/filespage.html @@ -0,0 +1,8 @@ +<html> +<body> +<p>Sometimes it can happen that the previously specified paths contain +more or other files than actually needed for the documentation.</p> +<p>This page lists all files which are likely to be unused because they +are neither referenced by any keyword nor be the TOC.</p> +</body> +</html> diff --git a/tools/assistant/tools/qhelpconverter/doc/filterpage.html b/tools/assistant/tools/qhelpconverter/doc/filterpage.html new file mode 100644 index 0000000..7b3781b --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/doc/filterpage.html @@ -0,0 +1,13 @@ +<html> +<body> +<p>The help system offers the possibility to filter all installed documentations +for certain <b>attributes</b>. Commonly specified attributes are e.g. the company +and product name as well as the product version.</p> +<p>The help engine and Assistant use <b>custom filters</b> to do the actual +documentation filtering. A custom filter is basically just a alias name for a +list of filter attributes. So, if e.g. the custom filter "MyFilter" lists +the attributes "mycompany, myproduct" then only the documentation with those +attributes will be shown.</p> +<p><b>Warning:</b> The filter attributes are case sensitive!</p> +</body> +</html> diff --git a/tools/assistant/tools/qhelpconverter/doc/generalpage.html b/tools/assistant/tools/qhelpconverter/doc/generalpage.html new file mode 100644 index 0000000..8d106be --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/doc/generalpage.html @@ -0,0 +1,10 @@ +<html> +<body> +<p>The <b>namespace</b> is needed to identify this documentation when having +several documentation sets installed in a collection.</p> +<p><b>Virtual</b> folders are used to enable file references between all +documents. Thereby, the virtual folder acts as the root path of all +documents, even if those are part of different documentation sets, +meaning listed under different namespaces.</p> +</body> +</html> diff --git a/tools/assistant/tools/qhelpconverter/doc/identifierpage.html b/tools/assistant/tools/qhelpconverter/doc/identifierpage.html new file mode 100644 index 0000000..952b88d --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/doc/identifierpage.html @@ -0,0 +1,17 @@ +<html> +<body> +<p><b>Identifiers</b> are mostly used to make keywords unique, but they can also +be used to specify keywords which should not be shown in the index. Identifiers +are especially help full when using context sensitive help and one keyword has +more links assigned to it.</p> +<p>E.g. consider the keyword "replace" in Qt. It is +included, among others, in QString and QList. To be able to retrieve the proper +documentation, there is an identifier "QString::replace" and one +"QList::replace".</p> +<p>A <b>global prefix</b>, e.g. "MyApp::" is set for all keywords independent +where they are located. When <b>inheriting</b> the prefix from the file name, +the keywords get the prefix "[filename]::" where the file name is taken from the +reference of the keyword. The file name is just the base name, i.e. without any +directory or extension.</p> +</body> +</html> diff --git a/tools/assistant/tools/qhelpconverter/doc/inputpage.html b/tools/assistant/tools/qhelpconverter/doc/inputpage.html new file mode 100644 index 0000000..4054c54 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/doc/inputpage.html @@ -0,0 +1,7 @@ +<html> +<body> +<p>Both, a .adp or .dcf file can be specified. If an .adp file is detected, +the wizard generates a Qt help collection file in addition to the help +project file.</p> +</body> +</html> diff --git a/tools/assistant/tools/qhelpconverter/doc/outputpage.html b/tools/assistant/tools/qhelpconverter/doc/outputpage.html new file mode 100644 index 0000000..332ef69 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/doc/outputpage.html @@ -0,0 +1,7 @@ +<html> +<body> +<p>The specified output files will be located in the same directory as the +.adp or .dcf file. The collection file will only be generated if the input +file was an .adp file.</p> +</body> +</html> diff --git a/tools/assistant/tools/qhelpconverter/doc/pathpage.html b/tools/assistant/tools/qhelpconverter/doc/pathpage.html new file mode 100644 index 0000000..95449b3 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/doc/pathpage.html @@ -0,0 +1,8 @@ +<html> +<body> +<p>The new help system uses, in contrast to the old Qt Assistant, compressed +help files containing all files (html files, images, stylesheets, ...) +necessary to display the documentation correctly.</p> +<p>To be able to find all those files, the source paths have to be given.</p> +</body> +</html> diff --git a/tools/assistant/tools/qhelpconverter/filespage.cpp b/tools/assistant/tools/qhelpconverter/filespage.cpp new file mode 100644 index 0000000..2963155 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/filespage.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui/QKeyEvent> +#include "filespage.h" + +QT_BEGIN_NAMESPACE + +FilesPage::FilesPage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Unreferenced Files")); + setSubTitle(tr("Remove files which are neither referenced " + "by a keyword nor by the TOC.")); + + m_ui.setupUi(this); + m_ui.fileListWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_ui.fileListWidget->installEventFilter(this); + connect(m_ui.removeButton, SIGNAL(clicked()), + this, SLOT(removeFile())); + connect(m_ui.removeAllButton, SIGNAL(clicked()), + this, SLOT(removeAllFiles())); + + m_ui.fileLabel->setText(tr("<p><b>Warning:</b> Be aware " + "when removing images or stylesheets since those files " + "are not directly referenced by the .adp or .dcf " + "file.</p>")); +} + +void FilesPage::setFilesToRemove(const QStringList &files) +{ + m_files = files; + m_ui.fileListWidget->clear(); + m_ui.fileListWidget->addItems(files); +} + +QStringList FilesPage::filesToRemove() const +{ + return m_filesToRemove; +} + +void FilesPage::removeFile() +{ + int row = m_ui.fileListWidget->currentRow() + - m_ui.fileListWidget->selectedItems().count() + 1; + foreach (const QListWidgetItem *item, m_ui.fileListWidget->selectedItems()) { + m_filesToRemove.append(item->text()); + delete item; + } + if (m_ui.fileListWidget->count() > row && row >= 0) + m_ui.fileListWidget->setCurrentRow(row); + else + m_ui.fileListWidget->setCurrentRow(m_ui.fileListWidget->count()); +} + +void FilesPage::removeAllFiles() +{ + m_ui.fileListWidget->clear(); + m_filesToRemove = m_files; +} + +bool FilesPage::eventFilter(QObject *obj, QEvent *event) +{ + if (obj == m_ui.fileListWidget && event->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast<QKeyEvent*>(event); + if (ke->key() == Qt::Key_Delete) { + removeFile(); + return true; + } + } + return QWizardPage::eventFilter(obj, event); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/qhelpconverter/filespage.h b/tools/assistant/tools/qhelpconverter/filespage.h new file mode 100644 index 0000000..584af87 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/filespage.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FILESPAGE_H +#define FILESPAGE_H + +#include <QtGui/QWizardPage> +#include "ui_filespage.h" + +QT_BEGIN_NAMESPACE + +class FilesPage : public QWizardPage +{ + Q_OBJECT + +public: + FilesPage(QWidget *parent = 0); + void setFilesToRemove(const QStringList &files); + QStringList filesToRemove() const; + +private slots: + void removeFile(); + void removeAllFiles(); + +private: + bool eventFilter(QObject *obj, QEvent *event); + + Ui::FilesPage m_ui; + QStringList m_files; + QStringList m_filesToRemove; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/tools/qhelpconverter/filespage.ui b/tools/assistant/tools/qhelpconverter/filespage.ui new file mode 100644 index 0000000..d308b96 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/filespage.ui @@ -0,0 +1,79 @@ +<ui version="4.0" > + <class>FilesPage</class> + <widget class="QWidget" name="FilesPage" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>417</width> + <height>242</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <layout class="QGridLayout" > + <item row="0" column="0" colspan="2" > + <widget class="QLabel" name="fileLabel" > + <property name="text" > + <string>Files:</string> + </property> + <property name="wordWrap" > + <bool>true</bool> + </property> + </widget> + </item> + <item rowspan="3" row="1" column="0" > + <widget class="QListWidget" name="fileListWidget" /> + </item> + <item row="1" column="1" > + <widget class="QPushButton" name="removeButton" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Maximum" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>Remove</string> + </property> + </widget> + </item> + <item row="2" column="1" > + <widget class="QPushButton" name="removeAllButton" > + <property name="text" > + <string>Remove All</string> + </property> + </widget> + </item> + <item row="3" column="1" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>75</width> + <height>16</height> + </size> + </property> + </spacer> + </item> + <item row="4" column="0" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>31</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/tools/assistant/tools/qhelpconverter/filterpage.cpp b/tools/assistant/tools/qhelpconverter/filterpage.cpp new file mode 100644 index 0000000..9f7e303 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/filterpage.cpp @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui/QMessageBox> +#include "filterpage.h" + +QT_BEGIN_NAMESPACE + +FilterPage::FilterPage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Filter Settings")); + setSubTitle(tr("Specify the filter attributes for the " + "documentation. If filter attributes are used, " + "also define a custom filter for it. Both, the " + "filter attributes and the custom filters are " + "optional.")); + + m_ui.setupUi(this); + m_ui.customFilterWidget->headerItem()->setText(0, tr("Filter Name")); + m_ui.customFilterWidget->headerItem()->setText(1, tr("Filter Attributes")); + m_ui.customFilterWidget->setRootIsDecorated(false); + m_ui.removeButton->setDisabled(true); + connect(m_ui.addButton, SIGNAL(clicked()), + this, SLOT(addFilter())); + connect(m_ui.removeButton, SIGNAL(clicked()), + this, SLOT(removeFilter())); +} + +bool FilterPage::validatePage() +{ + m_filterAttributes.clear(); + foreach (const QString &f, m_ui.filterLineEdit->text().split(QLatin1Char(','))) { + if (!f.trimmed().isEmpty()) + m_filterAttributes.append(f.trimmed()); + } + + m_customFilters.clear(); + QSet<QString> names; + QSet<QString> atts; + QString str; + CustomFilter customFilter; + QTreeWidgetItem *item = 0; + for (int i=0; i<m_ui.customFilterWidget->topLevelItemCount(); ++i) { + item = m_ui.customFilterWidget->topLevelItem(i); + str = item->text(0); + if (str.isEmpty() || names.contains(str)) { + QMessageBox::critical(this, tr("Custom Filters"), + tr("The custom filter \'%1\' is defined multiple times.") + .arg(str)); + return false; + } + names.insert(str); + customFilter.name = str; + + str.clear(); + QStringList lst; + foreach (const QString &s, item->text(1).split(QLatin1Char(','))) { + const QString st = s.trimmed(); + if (!st.isEmpty()) { + str += QLatin1Char(',') + st; + lst.append(st); + } + } + if (atts.contains(str)) { + QMessageBox::critical(this, tr("Custom Filters"), + tr("The attributes for custom filter \'%1\' are defined multiple times.") + .arg(customFilter.name)); + return false; + } + atts.insert(str); + customFilter.filterAttributes = lst; + m_customFilters.append(customFilter); + } + return true; +} + +QStringList FilterPage::filterAttributes() const +{ + return m_filterAttributes; +} + +QList<CustomFilter> FilterPage::customFilters() const +{ + return m_customFilters; +} + +void FilterPage::addFilter() +{ + QTreeWidgetItem *item = new QTreeWidgetItem(m_ui.customFilterWidget); + item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsEditable|Qt::ItemIsSelectable); + item->setText(0, QLatin1String("unfiltered")); + item->setText(1, QLatin1String("")); + m_ui.customFilterWidget->editItem(item, 0); + m_ui.removeButton->setDisabled(false); +} + +void FilterPage::removeFilter() +{ + QModelIndex idx = m_ui.customFilterWidget->currentIndex(); + if (!idx.isValid()) + return; + QTreeWidgetItem *item = m_ui.customFilterWidget->takeTopLevelItem(idx.row()); + delete item; + if (!m_ui.customFilterWidget->topLevelItemCount()) + m_ui.removeButton->setDisabled(true); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/qhelpconverter/filterpage.h b/tools/assistant/tools/qhelpconverter/filterpage.h new file mode 100644 index 0000000..5f0e1b1 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/filterpage.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FILTERPAGE_H +#define FILTERPAGE_H + +#include <QtGui/QWizardPage> +#include "ui_filterpage.h" + +QT_BEGIN_NAMESPACE + +struct CustomFilter +{ + QString name; + QStringList filterAttributes; +}; + +class FilterPage : public QWizardPage +{ + Q_OBJECT + +public: + FilterPage(QWidget *parent = 0); + QStringList filterAttributes() const; + QList<CustomFilter> customFilters() const; + +private slots: + void addFilter(); + void removeFilter(); + +private: + bool validatePage(); + + Ui::FilterPage m_ui; + QStringList m_filterAttributes; + QList<CustomFilter> m_customFilters; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/tools/qhelpconverter/filterpage.ui b/tools/assistant/tools/qhelpconverter/filterpage.ui new file mode 100644 index 0000000..7cda3d9 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/filterpage.ui @@ -0,0 +1,125 @@ +<ui version="4.0" > + <class>FilterPage</class> + <widget class="QWidget" name="FilterPage" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>419</width> + <height>243</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <layout class="QGridLayout" > + <item row="1" column="0" > + <widget class="QLabel" name="label" > + <property name="text" > + <string>Filter attributes for current documentation (comma separated list):</string> + </property> + </widget> + </item> + <item row="2" column="0" > + <widget class="QLineEdit" name="filterLineEdit" /> + </item> + <item row="4" column="0" > + <widget class="QGroupBox" name="groupBox" > + <property name="title" > + <string>Custom Filters</string> + </property> + <layout class="QGridLayout" > + <item rowspan="3" row="0" column="0" > + <widget class="QTreeWidget" name="customFilterWidget" > + <property name="columnCount" > + <number>2</number> + </property> + <column> + <property name="text" > + <string>1</string> + </property> + </column> + <column> + <property name="text" > + <string>2</string> + </property> + </column> + </widget> + </item> + <item row="0" column="1" > + <widget class="QPushButton" name="addButton" > + <property name="text" > + <string>Add</string> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QPushButton" name="removeButton" > + <property name="text" > + <string>Remove</string> + </property> + </widget> + </item> + <item row="2" column="1" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + <item row="0" column="0" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item row="5" column="0" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <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>10</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/tools/assistant/tools/qhelpconverter/finishpage.cpp b/tools/assistant/tools/qhelpconverter/finishpage.cpp new file mode 100644 index 0000000..0b3c33f --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/finishpage.cpp @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui/QTextEdit> +#include <QtGui/QLayout> +#include <QtGui/QSpacerItem> +#include <QtGui/QApplication> + +#include "finishpage.h" + +QT_BEGIN_NAMESPACE + +FinishPage::FinishPage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Converting File")); + setSubTitle(QLatin1String("Creating the new Qt help files from the " + "old .adp file.")); + setFinalPage(true); + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, + QSizePolicy::Fixed)); + + m_textEdit = new QTextEdit(); + layout->addWidget(m_textEdit); + + layout->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, + QSizePolicy::Expanding)); +} + +void FinishPage::appendMessage(const QString &msg) +{ + m_textEdit->append(msg); + qApp->processEvents(); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/qhelpconverter/finishpage.h b/tools/assistant/tools/qhelpconverter/finishpage.h new file mode 100644 index 0000000..7a4689d --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/finishpage.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FINISHPAGE_H +#define FINISHPAGE_H + +#include <QtGui/QWizardPage> + +QT_BEGIN_NAMESPACE + +class QTextEdit; + +class FinishPage : public QWizardPage +{ + Q_OBJECT + +public: + FinishPage(QWidget *parent = 0); + void appendMessage(const QString &msg); + +private: + QTextEdit *m_textEdit; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/tools/qhelpconverter/generalpage.cpp b/tools/assistant/tools/qhelpconverter/generalpage.cpp new file mode 100644 index 0000000..f59be49 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/generalpage.cpp @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui/QMessageBox> +#include "generalpage.h" + +QT_BEGIN_NAMESPACE + +GeneralPage::GeneralPage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("General Settings")); + setSubTitle(tr("Specify the namespace and the virtual " + "folder for the documentation.")); + + m_ui.setupUi(this); + connect(m_ui.namespaceLineEdit, SIGNAL(textChanged(const QString&)), + this, SIGNAL(completeChanged())); + connect(m_ui.folderLineEdit, SIGNAL(textChanged(const QString&)), + this, SIGNAL(completeChanged())); + + m_ui.namespaceLineEdit->setText(QLatin1String("mycompany.com")); + m_ui.folderLineEdit->setText(QLatin1String("product_1.0")); + + registerField(QLatin1String("namespaceName"), m_ui.namespaceLineEdit); + registerField(QLatin1String("virtualFolder"), m_ui.folderLineEdit); +} + +bool GeneralPage::isComplete() const +{ + if (m_ui.namespaceLineEdit->text().isEmpty() + || m_ui.folderLineEdit->text().isEmpty()) + return false; + return true; +} + +bool GeneralPage::validatePage() +{ + QString s = m_ui.namespaceLineEdit->text(); + if (s.contains(QLatin1Char('/')) || s.contains(QLatin1Char('\\'))) { + QMessageBox::critical(this, tr("Namespace Error"), + tr("The namespace contains some invalid characters.")); + return false; + } + s = m_ui.folderLineEdit->text(); + if (s.contains(QLatin1Char('/')) || s.contains(QLatin1Char('\\'))) { + QMessageBox::critical(this, tr("Virtual Folder Error"), + tr("The virtual folder contains some invalid characters.")); + return false; + } + return true; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/qhelpconverter/generalpage.h b/tools/assistant/tools/qhelpconverter/generalpage.h new file mode 100644 index 0000000..c9d2b4d --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/generalpage.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef GENERALPAGE_H +#define GENERALPAGE_H + +#include <QtGui/QWizardPage> +#include "ui_generalpage.h" + +QT_BEGIN_NAMESPACE + +class GeneralPage : public QWizardPage +{ + Q_OBJECT + +public: + GeneralPage(QWidget *parent = 0); + +private: + bool validatePage(); + bool isComplete() const; + + Ui::GeneralPage m_ui; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/tools/qhelpconverter/generalpage.ui b/tools/assistant/tools/qhelpconverter/generalpage.ui new file mode 100644 index 0000000..9c2babb --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/generalpage.ui @@ -0,0 +1,69 @@ +<ui version="4.0" > + <class>GeneralPage</class> + <widget class="QWidget" name="GeneralPage" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>417</width> + <height>243</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <layout class="QGridLayout" > + <item row="1" column="0" > + <widget class="QLabel" name="label" > + <property name="text" > + <string>Namespace:</string> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QLineEdit" name="namespaceLineEdit" /> + </item> + <item row="2" column="0" > + <widget class="QLabel" name="label_2" > + <property name="text" > + <string>Virtual Folder:</string> + </property> + </widget> + </item> + <item row="2" column="1" > + <widget class="QLineEdit" name="folderLineEdit" /> + </item> + <item row="0" column="1" > + <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="3" column="1" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/tools/assistant/tools/qhelpconverter/helpwindow.cpp b/tools/assistant/tools/qhelpconverter/helpwindow.cpp new file mode 100644 index 0000000..b41a410 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/helpwindow.cpp @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QFile> +#include <QtCore/QTextStream> +#include <QtGui/QVBoxLayout> +#include <QtGui/QLabel> +#include <QtGui/QTextEdit> + +#include "helpwindow.h" + +QT_BEGIN_NAMESPACE + +HelpWindow::HelpWindow(QWidget *parent) + : QWidget(parent, 0) +{ + setAutoFillBackground(true); + QVBoxLayout *layout = new QVBoxLayout(this); + layout->setMargin(0); + QFrame *frame = new QFrame(this); + QPalette p = palette(); + p.setColor(QPalette::Background, Qt::white); + setPalette(p); + frame->setFrameStyle(QFrame::Box | QFrame::Plain); + layout->addWidget(frame); + + layout = new QVBoxLayout(frame); + layout->setMargin(2); + QLabel *l = new QLabel(QLatin1String("<center><b>Wizard Assistant</b></center>")); + layout->addWidget(l); + m_textEdit = new QTextEdit(); + m_textEdit->setFrameStyle(QFrame::NoFrame); + m_textEdit->setReadOnly(true); + layout->addWidget(m_textEdit); +} + +void HelpWindow::setHelp(const QString &topic) +{ + QLatin1String fileStr(":/trolltech/qhelpconverter/doc/%1.html"); + QFile f(QString(fileStr).arg(topic.toLower())); + f.open(QIODevice::ReadOnly); + QTextStream s(&f); + m_textEdit->setText(s.readAll()); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/qhelpconverter/helpwindow.h b/tools/assistant/tools/qhelpconverter/helpwindow.h new file mode 100644 index 0000000..9c0866a --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/helpwindow.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef HELPWINDOW_H +#define HELPWINDOW_H + +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE + +class QTextEdit; + +class HelpWindow : public QWidget +{ + Q_OBJECT + +public: + HelpWindow(QWidget *parent = 0); + void setHelp(const QString &topic); + +private: + QTextEdit *m_textEdit; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/tools/qhelpconverter/identifierpage.cpp b/tools/assistant/tools/qhelpconverter/identifierpage.cpp new file mode 100644 index 0000000..64a23a6 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/identifierpage.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "identifierpage.h" + +QT_BEGIN_NAMESPACE + +IdentifierPage::IdentifierPage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Identifiers")); + setSubTitle(tr("This page allows you to create identifiers from " + "the keywords found in the .adp or .dcf file.")); + + m_ui.setupUi(this); + + connect(m_ui.identifierCheckBox, SIGNAL(toggled(bool)), + this, SLOT(setupButtons(bool))); + + registerField(QLatin1String("createIdentifier"), m_ui.identifierCheckBox); + registerField(QLatin1String("globalPrefix"), m_ui.prefixLineEdit); + registerField(QLatin1String("fileNamePrefix"), m_ui.fileNameButton); +} + +void IdentifierPage::setupButtons(bool checked) +{ + m_ui.globalButton->setEnabled(checked); + m_ui.fileNameButton->setEnabled(checked); + m_ui.prefixLineEdit->setEnabled(checked + && m_ui.globalButton->isChecked()); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/qhelpconverter/identifierpage.h b/tools/assistant/tools/qhelpconverter/identifierpage.h new file mode 100644 index 0000000..fcebb49 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/identifierpage.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef IDENTIFIERPAGE_H +#define IDENTIFIERPAGE_H + +#include <QtGui/QWizardPage> +#include "ui_identifierpage.h" + +QT_BEGIN_NAMESPACE + +class IdentifierPage : public QWizardPage +{ + Q_OBJECT + +public: + IdentifierPage(QWidget *parent = 0); + +private slots: + void setupButtons(bool checked); + +private: + Ui::IdentifierPage m_ui; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/tools/qhelpconverter/identifierpage.ui b/tools/assistant/tools/qhelpconverter/identifierpage.ui new file mode 100644 index 0000000..cd0df75 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/identifierpage.ui @@ -0,0 +1,132 @@ +<ui version="4.0" > + <class>IdentifierPage</class> + <widget class="QWidget" name="IdentifierPage" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>417</width> + <height>242</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <layout class="QGridLayout" > + <item row="0" column="1" > + <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="1" column="0" colspan="3" > + <widget class="QCheckBox" name="identifierCheckBox" > + <property name="text" > + <string>Create identifiers</string> + </property> + </widget> + </item> + <item row="1" column="3" > + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" > + <size> + <width>161</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="0" > + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType" > + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" > + <size> + <width>30</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="1" > + <widget class="QRadioButton" name="globalButton" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="text" > + <string>Global prefix:</string> + </property> + <property name="checked" > + <bool>true</bool> + </property> + </widget> + </item> + <item row="2" column="2" > + <widget class="QLineEdit" name="prefixLineEdit" > + <property name="enabled" > + <bool>false</bool> + </property> + </widget> + </item> + <item row="3" column="1" colspan="2" > + <widget class="QRadioButton" name="fileNameButton" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="text" > + <string>Inherit prefix from file names</string> + </property> + </widget> + </item> + <item row="4" column="1" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>31</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>globalButton</sender> + <signal>toggled(bool)</signal> + <receiver>prefixLineEdit</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel" > + <x>122</x> + <y>72</y> + </hint> + <hint type="destinationlabel" > + <x>161</x> + <y>71</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/tools/assistant/tools/qhelpconverter/inputpage.cpp b/tools/assistant/tools/qhelpconverter/inputpage.cpp new file mode 100644 index 0000000..5872523 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/inputpage.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QFile> +#include <QtCore/QVariant> + +#include <QtGui/QLayout> +#include <QtGui/QLabel> +#include <QtGui/QLineEdit> +#include <QtGui/QToolButton> +#include <QtGui/QFileDialog> +#include <QtGui/QMessageBox> +#include <QtGui/QApplication> + +#include "inputpage.h" +#include "adpreader.h" + +QT_BEGIN_NAMESPACE + +InputPage::InputPage(AdpReader *reader, QWidget *parent) + : QWizardPage(parent) +{ + m_adpReader = reader; + setTitle(tr("Input File")); + setSubTitle(tr("Specify the .adp or .dcf file you want " + "to convert to the new Qt help project format and/or " + "collection format.")); + + m_ui.setupUi(this); + connect(m_ui.browseButton, SIGNAL(clicked()), + this, SLOT(getFileName())); + + registerField(QLatin1String("adpFileName"), m_ui.fileLineEdit); +} + +void InputPage::getFileName() +{ + QString f = QFileDialog::getOpenFileName(this, tr("Open file"), QString(), + tr("Qt Help Files (*.adp *.dcf)")); + if (!f.isEmpty()) + m_ui.fileLineEdit->setText(f); +} + +bool InputPage::validatePage() +{ + QFile f(m_ui.fileLineEdit->text().trimmed()); + if (!f.exists() || !f.open(QIODevice::ReadOnly)) { + QMessageBox::critical(this, tr("File Open Error"), + tr("The specified file could not be opened!")); + return false; + } + + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + m_adpReader->readData(f.readAll()); + QApplication::restoreOverrideCursor(); + if (m_adpReader->hasError()) { + QMessageBox::critical(this, tr("File Parsing Error"), + tr("Parsing error in line %1!").arg(m_adpReader->lineNumber())); + return false; + } + + return true; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/qhelpconverter/inputpage.h b/tools/assistant/tools/qhelpconverter/inputpage.h new file mode 100644 index 0000000..dddf80d --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/inputpage.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef INPUTPAGE_H +#define INPUTPAGE_H + +#include <QtGui/QWizardPage> +#include "ui_inputpage.h" + +QT_BEGIN_NAMESPACE + +class AdpReader; + +class InputPage : public QWizardPage +{ + Q_OBJECT + +public: + InputPage(AdpReader *reader, QWidget *parent = 0); + +private slots: + void getFileName(); + +private: + bool validatePage(); + + Ui::InputPage m_ui; + AdpReader *m_adpReader; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/tools/qhelpconverter/inputpage.ui b/tools/assistant/tools/qhelpconverter/inputpage.ui new file mode 100644 index 0000000..e7cd3a0 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/inputpage.ui @@ -0,0 +1,79 @@ +<ui version="4.0" > + <class>InputPage</class> + <widget class="QWidget" name="InputPage" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>417</width> + <height>242</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <layout class="QGridLayout" > + <item row="0" column="2" > + <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="1" column="0" > + <widget class="QLabel" name="label" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Preferred" hsizetype="Maximum" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>File name:</string> + </property> + </widget> + </item> + <item row="1" column="1" colspan="2" > + <layout class="QHBoxLayout" > + <property name="spacing" > + <number>0</number> + </property> + <item> + <widget class="QLineEdit" name="fileLineEdit" /> + </item> + <item> + <widget class="QToolButton" name="browseButton" > + <property name="text" > + <string>...</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="2" column="1" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>31</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/tools/assistant/tools/qhelpconverter/main.cpp b/tools/assistant/tools/qhelpconverter/main.cpp new file mode 100644 index 0000000..2b0f602 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/main.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QFileInfo> +#include <QtGui/QApplication> + +#include "conversionwizard.h" + +QT_USE_NAMESPACE + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + ConversionWizard w; + if (argc == 2) { + QFileInfo fi(QString::fromLocal8Bit(argv[1])); + if (fi.exists()) + w.setAdpFileName(fi.absoluteFilePath()); + } + w.show(); + return app.exec(); +} + diff --git a/tools/assistant/tools/qhelpconverter/outputpage.cpp b/tools/assistant/tools/qhelpconverter/outputpage.cpp new file mode 100644 index 0000000..77cbf4c --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/outputpage.cpp @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QFileInfo> +#include <QtCore/QDir> +#include <QtGui/QMessageBox> + +#include "outputpage.h" + +QT_BEGIN_NAMESPACE + +OutputPage::OutputPage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Output File Names")); + setSubTitle(tr("Specify the file names for the output files.")); + setButtonText(QWizard::NextButton, tr("Convert...")); + + m_ui.setupUi(this); + connect(m_ui.projectLineEdit, SIGNAL(textChanged(const QString&)), + this, SIGNAL(completeChanged())); + connect(m_ui.collectionLineEdit, SIGNAL(textChanged(const QString&)), + this, SIGNAL(completeChanged())); + + registerField(QLatin1String("ProjectFileName"), + m_ui.projectLineEdit); + registerField(QLatin1String("CollectionFileName"), + m_ui.collectionLineEdit); +} + +void OutputPage::setPath(const QString &path) +{ + m_path = path; +} + +void OutputPage::setCollectionComponentEnabled(bool enabled) +{ + m_ui.collectionLineEdit->setEnabled(enabled); + m_ui.label_2->setEnabled(enabled); +} + +bool OutputPage::isComplete() const +{ + if (m_ui.projectLineEdit->text().isEmpty() + || m_ui.collectionLineEdit->text().isEmpty()) + return false; + return true; +} + +bool OutputPage::validatePage() +{ + return checkFile(m_ui.projectLineEdit->text(), + tr("Qt Help Project File")) + && checkFile(m_ui.collectionLineEdit->text(), + tr("Qt Help Collection Project File")); +} + +bool OutputPage::checkFile(const QString &fileName, const QString &title) +{ + QFile fi(m_path + QDir::separator() + fileName); + if (!fi.exists()) + return true; + + if (QMessageBox::warning(this, title, + tr("The specified file %1 already exist.\n\nDo you want to remove it?") + .arg(fileName), tr("Remove"), tr("Cancel")) == 0) { + return fi.remove(); + } + return false; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/qhelpconverter/outputpage.h b/tools/assistant/tools/qhelpconverter/outputpage.h new file mode 100644 index 0000000..3907ae5 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/outputpage.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef OUTPUTPAGE_H +#define OUTPUTPAGE_H + +#include <QtGui/QWizardPage> +#include "ui_outputpage.h" + +QT_BEGIN_NAMESPACE + +class OutputPage : public QWizardPage +{ + Q_OBJECT + +public: + OutputPage(QWidget *parent = 0); + void setPath(const QString &path); + void setCollectionComponentEnabled(bool enabled); + +private: + bool isComplete() const; + bool validatePage(); + bool checkFile(const QString &fileName, + const QString &title); + + Ui::OutputPage m_ui; + QString m_path; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/tools/qhelpconverter/outputpage.ui b/tools/assistant/tools/qhelpconverter/outputpage.ui new file mode 100644 index 0000000..755f818 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/outputpage.ui @@ -0,0 +1,95 @@ +<ui version="4.0" > + <class>OutputPage</class> + <widget class="QWidget" name="OutputPage" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>417</width> + <height>242</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <layout class="QGridLayout" > + <item row="0" column="1" > + <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="1" column="0" > + <widget class="QLabel" name="label" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Preferred" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>Project file name:</string> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QLineEdit" name="projectLineEdit" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Expanding" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item row="2" column="0" > + <widget class="QLabel" name="label_2" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Preferred" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>Collection file name:</string> + </property> + </widget> + </item> + <item row="2" column="1" > + <widget class="QLineEdit" name="collectionLineEdit" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Expanding" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item row="3" column="1" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/tools/assistant/tools/qhelpconverter/pathpage.cpp b/tools/assistant/tools/qhelpconverter/pathpage.cpp new file mode 100644 index 0000000..83019d6 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/pathpage.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui/QFileDialog> + +#include "pathpage.h" + +QT_BEGIN_NAMESPACE + +PathPage::PathPage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Source File Paths")); + setSubTitle(tr("Specify the paths where the sources files " + "are located. By default, all files in those directories " + "matched by the file filter will be included.")); + + m_ui.setupUi(this); + connect(m_ui.addButton, SIGNAL(clicked()), + this, SLOT(addPath())); + connect(m_ui.removeButton, SIGNAL(clicked()), + this, SLOT(removePath())); + + m_ui.filterLineEdit->setText(QLatin1String("*.html, *.htm, *.png, *.jpg, *.css")); + + registerField(QLatin1String("sourcePathList"), m_ui.pathListWidget); + m_firstTime = true; +} + +void PathPage::setPath(const QString &path) +{ + if (!m_firstTime) + return; + + m_ui.pathListWidget->addItem(path); + m_firstTime = false; + m_ui.pathListWidget->setCurrentRow(0); +} + +QStringList PathPage::paths() const +{ + QStringList lst; + for (int i = 0; i<m_ui.pathListWidget->count(); ++i) + lst.append(m_ui.pathListWidget->item(i)->text()); + return lst; +} + +QStringList PathPage::filters() const +{ + QStringList lst; + foreach (const QString &s, m_ui.filterLineEdit->text().split(QLatin1Char(','))) { + lst.append(s.trimmed()); + } + return lst; +} + +void PathPage::addPath() +{ + QString dir = QFileDialog::getExistingDirectory(this, + tr("Source File Path")); + if (!dir.isEmpty()) + m_ui.pathListWidget->addItem(dir); +} + +void PathPage::removePath() +{ + QListWidgetItem *i = m_ui.pathListWidget + ->takeItem(m_ui.pathListWidget->currentRow()); + delete i; + if (!m_ui.pathListWidget->count()) + m_ui.removeButton->setEnabled(false); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/qhelpconverter/pathpage.h b/tools/assistant/tools/qhelpconverter/pathpage.h new file mode 100644 index 0000000..e081b73 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/pathpage.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PATHPAGE_H +#define PATHPAGE_H + +#include <QtGui/QWizardPage> +#include "ui_pathpage.h" + +QT_BEGIN_NAMESPACE + +class PathPage : public QWizardPage +{ + Q_OBJECT + +public: + PathPage(QWidget *parent = 0); + void setPath(const QString &path); + QStringList paths() const; + QStringList filters() const; + +private slots: + void addPath(); + void removePath(); + +private: + Ui::PathPage m_ui; + bool m_firstTime; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/tools/qhelpconverter/pathpage.ui b/tools/assistant/tools/qhelpconverter/pathpage.ui new file mode 100644 index 0000000..8908391 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/pathpage.ui @@ -0,0 +1,114 @@ +<ui version="4.0" > + <class>PathPage</class> + <widget class="QWidget" name="PathPage" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>417</width> + <height>243</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <layout class="QGridLayout" > + <item row="0" column="0" > + <widget class="QLabel" name="label_2" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Preferred" hsizetype="Maximum" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>File filters:</string> + </property> + </widget> + </item> + <item row="0" column="1" colspan="2" > + <widget class="QLineEdit" name="filterLineEdit" /> + </item> + <item row="1" column="1" > + <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>10</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="0" colspan="3" > + <widget class="QLabel" name="label" > + <property name="text" > + <string>Documentation source file paths:</string> + </property> + </widget> + </item> + <item rowspan="3" row="3" column="0" colspan="3" > + <widget class="QListWidget" name="pathListWidget" /> + </item> + <item row="3" column="3" > + <widget class="QPushButton" name="addButton" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Maximum" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>Add</string> + </property> + </widget> + </item> + <item row="4" column="3" > + <widget class="QPushButton" name="removeButton" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Maximum" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>Remove</string> + </property> + </widget> + </item> + <item row="5" column="3" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>51</height> + </size> + </property> + </spacer> + </item> + <item row="6" column="2" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>31</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/tools/assistant/tools/qhelpconverter/qhcpwriter.cpp b/tools/assistant/tools/qhelpconverter/qhcpwriter.cpp new file mode 100644 index 0000000..55a1b12 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/qhcpwriter.cpp @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QFile> + +#include "qhcpwriter.h" + +QT_BEGIN_NAMESPACE + +QhcpWriter::QhcpWriter() +{ + setAutoFormatting(true); +} + +void QhcpWriter::setHelpProjectFile(const QString &qhpFile) +{ + m_qhpFile = qhpFile; +} + +void QhcpWriter::setProperties(const QMap<QString, QString> props) +{ + m_properties = props; +} + +void QhcpWriter::setTitlePath(const QString &path) +{ + m_titlePath = path; +} + +bool QhcpWriter::writeFile(const QString &fileName) +{ + QFile out(fileName); + if (!out.open(QIODevice::WriteOnly)) + return false; + + setDevice(&out); + writeStartDocument(); + writeStartElement(QLatin1String("QHelpCollectionProject")); + writeAttribute(QLatin1String("version"), QLatin1String("1.0")); + writeAssistantSettings(); + writeDocuments(); + writeEndDocument(); + return true; +} + +void QhcpWriter::writeAssistantSettings() +{ + if (m_properties.isEmpty()) + return; + + writeStartElement(QLatin1String("assistant")); + + if (m_properties.contains(QLatin1String("title"))) + writeTextElement(QLatin1String("title"), m_properties.value(QLatin1String("title"))); + if (m_properties.contains(QLatin1String("applicationicon"))) + writeTextElement(QLatin1String("applicationIcon"), + m_properties.value(QLatin1String("applicationicon"))); + if (m_properties.contains(QLatin1String("startpage"))) + writeTextElement(QLatin1String("startPage"), m_titlePath + QLatin1String("/") + + m_properties.value(QLatin1String("startpage"))); + if (m_properties.contains(QLatin1String("aboutmenutext"))) { + writeStartElement(QLatin1String("aboutMenuText")); + writeTextElement(QLatin1String("text"), + m_properties.value(QLatin1String("aboutmenutext"))); + writeEndElement(); + } + if (m_properties.contains(QLatin1String("abouturl"))) { + writeStartElement(QLatin1String("aboutDialog")); + writeTextElement(QLatin1String("file"), m_properties.value(QLatin1String("abouturl"))); + writeEndElement(); + } + if (m_properties.contains(QLatin1String("name"))) { + writeTextElement(QLatin1String("cacheDirectory"), + QLatin1String(".") + m_properties.value(QLatin1String("name"))); + } + + writeEndElement(); +} + +void QhcpWriter::writeDocuments() +{ + if (m_qhpFile.isEmpty()) + return; + + QString out = m_qhpFile; + int i = out.indexOf(QLatin1Char('.')); + if (i > -1) + out = out.left(i); + out.append(QLatin1String(".qch")); + + writeStartElement(QLatin1String("docFiles")); + + writeStartElement(QLatin1String("generate")); + writeStartElement(QLatin1String("file")); + writeTextElement(QLatin1String("input"), m_qhpFile); + writeTextElement(QLatin1String("output"), out); + writeEndElement(); + writeEndElement(); + + writeStartElement(QLatin1String("register")); + writeTextElement(QLatin1String("file"), out); + writeEndElement(); + + writeEndElement(); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/qhelpconverter/qhcpwriter.h b/tools/assistant/tools/qhelpconverter/qhcpwriter.h new file mode 100644 index 0000000..ba448a5 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/qhcpwriter.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHCPWRITER_H +#define QHCPWRITER_H + +#include <QtXml/QXmlStreamWriter> +#include "adpreader.h" + +QT_BEGIN_NAMESPACE + +class QhcpWriter : public QXmlStreamWriter +{ +public: + QhcpWriter(); + bool writeFile(const QString &fileName); + void setHelpProjectFile(const QString &qhpFile); + void setProperties(const QMap<QString, QString> props); + void setTitlePath(const QString &path); + +private: + void writeAssistantSettings(); + void writeDocuments(); + + QString m_qhpFile; + QMap<QString, QString> m_properties; + QString m_titlePath; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/tools/qhelpconverter/qhelpconverter.pro b/tools/assistant/tools/qhelpconverter/qhelpconverter.pro new file mode 100644 index 0000000..341faf3 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/qhelpconverter.pro @@ -0,0 +1,47 @@ +QT += xml +TEMPLATE = app +TARGET = qhelpconverter +DESTDIR = ../../../../bin +CONFIG += qt warn_on help + +target.path=$$[QT_INSTALL_BINS] +INSTALLS += target + +SOURCES += conversionwizard.cpp \ + inputpage.cpp \ + generalpage.cpp \ + filterpage.cpp \ + identifierpage.cpp \ + pathpage.cpp \ + filespage.cpp \ + outputpage.cpp \ + finishpage.cpp \ + adpreader.cpp \ + qhpwriter.cpp \ + qhcpwriter.cpp \ + helpwindow.cpp \ + main.cpp + +HEADERS += conversionwizard.h \ + inputpage.h \ + generalpage.h \ + filterpage.h \ + identifierpage.h \ + pathpage.h \ + filespage.h \ + outputpage.h \ + finishpage.h \ + adpreader.h \ + qhcpwriter.h \ + qhpwriter.h \ + helpwindow.h + +FORMS += inputpage.ui \ + generalpage.ui \ + filterpage.ui \ + identifierpage.ui \ + pathpage.ui \ + filespage.ui \ + outputpage.ui + +RESOURCES += qhelpconverter.qrc diff --git a/tools/assistant/tools/qhelpconverter/qhelpconverter.qrc b/tools/assistant/tools/qhelpconverter/qhelpconverter.qrc new file mode 100644 index 0000000..e2a68ab --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/qhelpconverter.qrc @@ -0,0 +1,13 @@ +<RCC> + <qresource prefix="/trolltech/qhelpconverter" > + <file>assistant-128.png</file> + <file>assistant.png</file> + <file>doc/inputpage.html</file> + <file>doc/generalpage.html</file> + <file>doc/filterpage.html</file> + <file>doc/identifierpage.html</file> + <file>doc/pathpage.html</file> + <file>doc/filespage.html</file> + <file>doc/outputpage.html</file> + </qresource> +</RCC> diff --git a/tools/assistant/tools/qhelpconverter/qhpwriter.cpp b/tools/assistant/tools/qhelpconverter/qhpwriter.cpp new file mode 100644 index 0000000..cd54537 --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/qhpwriter.cpp @@ -0,0 +1,184 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QFile> + +#include "qhpwriter.h" +#include "adpreader.h" + +QT_BEGIN_NAMESPACE + +QhpWriter::QhpWriter(const QString &namespaceName, + const QString &virtualFolder) +{ + m_namespaceName = namespaceName; + m_virtualFolder = virtualFolder; + setAutoFormatting(true); +} + +void QhpWriter::setAdpReader(AdpReader *reader) +{ + m_adpReader = reader; +} + +void QhpWriter::setFilterAttributes(const QStringList &attributes) +{ + m_filterAttributes = attributes; +} + +void QhpWriter::setCustomFilters(const QList<CustomFilter> filters) +{ + m_customFilters = filters; +} + +void QhpWriter::setFiles(const QStringList &files) +{ + m_files = files; +} + +void QhpWriter::generateIdentifiers(IdentifierPrefix prefix, + const QString prefixString) +{ + m_prefix = prefix; + m_prefixString = prefixString; +} + +bool QhpWriter::writeFile(const QString &fileName) +{ + QFile out(fileName); + if (!out.open(QIODevice::WriteOnly)) + return false; + + setDevice(&out); + writeStartDocument(); + writeStartElement(QLatin1String("QtHelpProject")); + writeAttribute(QLatin1String("version"), QLatin1String("1.0")); + writeTextElement(QLatin1String("namespace"), m_namespaceName); + writeTextElement(QLatin1String("virtualFolder"), m_virtualFolder); + writeCustomFilters(); + writeFilterSection(); + writeEndDocument(); + + out.close(); + return true; +} + +void QhpWriter::writeCustomFilters() +{ + if (!m_customFilters.count()) + return; + + foreach (const CustomFilter &f, m_customFilters) { + writeStartElement(QLatin1String("customFilter")); + writeAttribute(QLatin1String("name"), f.name); + foreach (const QString &a, f.filterAttributes) + writeTextElement(QLatin1String("filterAttribute"), a); + writeEndElement(); + } +} + +void QhpWriter::writeFilterSection() +{ + writeStartElement(QLatin1String("filterSection")); + foreach (const QString &a, m_filterAttributes) + writeTextElement(QLatin1String("filterAttribute"), a); + + writeToc(); + writeKeywords(); + writeFiles(); + writeEndElement(); +} + +void QhpWriter::writeToc() +{ + QList<ContentItem> lst = m_adpReader->contents(); + if (lst.isEmpty()) + return; + + int depth = -1; + writeStartElement(QLatin1String("toc")); + foreach (const ContentItem &i, lst) { + while (depth-- >= i.depth) + writeEndElement(); + writeStartElement(QLatin1String("section")); + writeAttribute(QLatin1String("title"), i.title); + writeAttribute(QLatin1String("ref"), i.reference); + depth = i.depth; + } + while (depth-- >= -1) + writeEndElement(); +} + +void QhpWriter::writeKeywords() +{ + QList<KeywordItem> lst = m_adpReader->keywords(); + if (lst.isEmpty()) + return; + + writeStartElement(QLatin1String("keywords")); + foreach (const KeywordItem &i, lst) { + writeEmptyElement(QLatin1String("keyword")); + writeAttribute(QLatin1String("name"), i.keyword); + writeAttribute(QLatin1String("ref"), i.reference); + if (m_prefix == FilePrefix) { + QString str = i.reference.mid( + i.reference.lastIndexOf(QLatin1Char('/'))+1); + str = str.left(str.lastIndexOf(QLatin1Char('.'))); + writeAttribute(QLatin1String("id"), str + QLatin1String("::") + i.keyword); + } else if (m_prefix == GlobalPrefix) { + writeAttribute(QLatin1String("id"), m_prefixString + i.keyword); + } + } + writeEndElement(); +} + +void QhpWriter::writeFiles() +{ + if (m_files.isEmpty()) + return; + + writeStartElement(QLatin1String("files")); + foreach (const QString &f, m_files) + writeTextElement(QLatin1String("file"), f); + writeEndElement(); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/qhelpconverter/qhpwriter.h b/tools/assistant/tools/qhelpconverter/qhpwriter.h new file mode 100644 index 0000000..bba3fcb --- /dev/null +++ b/tools/assistant/tools/qhelpconverter/qhpwriter.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHPWRITER_H +#define QHPWRITER_H + +#include <QtXml/QXmlStreamWriter> +#include "filterpage.h" + +QT_BEGIN_NAMESPACE + +class AdpReader; + +class QhpWriter : public QXmlStreamWriter +{ +public: + enum IdentifierPrefix {SkipAll, FilePrefix, GlobalPrefix}; + QhpWriter(const QString &namespaceName, + const QString &virtualFolder); + void setAdpReader(AdpReader *reader); + void setFilterAttributes(const QStringList &attributes); + void setCustomFilters(const QList<CustomFilter> filters); + void setFiles(const QStringList &files); + void generateIdentifiers(IdentifierPrefix prefix, + const QString prefixString = QString()); + bool writeFile(const QString &fileName); + +private: + void writeCustomFilters(); + void writeFilterSection(); + void writeToc(); + void writeKeywords(); + void writeFiles(); + + QString m_namespaceName; + QString m_virtualFolder; + AdpReader *m_adpReader; + QStringList m_filterAttributes; + QList<CustomFilter> m_customFilters; + QStringList m_files; + IdentifierPrefix m_prefix; + QString m_prefixString; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/tools/qhelpgenerator/main.cpp b/tools/assistant/tools/qhelpgenerator/main.cpp new file mode 100644 index 0000000..42a1595 --- /dev/null +++ b/tools/assistant/tools/qhelpgenerator/main.cpp @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../shared/helpgenerator.h" + +#include <QtCore/QDir> +#include <QtCore/QFileInfo> +#include <QtCore/QCoreApplication> + +#include <private/qhelpprojectdata_p.h> + +QT_USE_NAMESPACE + +int main(int argc, char *argv[]) +{ + QString error; + QString arg; + QString compressedFile; + QString projectFile; + QString basePath; + bool showHelp = false; + bool showVersion = false; + + for (int i = 1; i < argc; ++i) { + arg = QString::fromLocal8Bit(argv[i]); + if (arg == QLatin1String("-o")) { + if (++i < argc) { + QFileInfo fi(QString::fromLocal8Bit(argv[i])); + compressedFile = fi.absoluteFilePath(); + } else { + error = QObject::tr("Missing output file name!"); + } + } else if (arg == QLatin1String("-v")) { + showVersion = true; + } else if (arg == QLatin1String("-h")) { + showHelp = true; + } else { + QFileInfo fi(arg); + projectFile = fi.absoluteFilePath(); + basePath = fi.absolutePath(); + } + } + + if (showVersion) { + 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!"); + + QString help = QObject::tr("\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" + " -v Displays the version of \n" + " qhelpgenerator.\n\n"); + + if (showHelp) { + fprintf(stdout, "%s", qPrintable(help)); + return 0; + }else if (!error.isEmpty()) { + fprintf(stderr, "%s\n\n%s", qPrintable(error), qPrintable(help)); + return -1; + } + + QFile file(projectFile); + if (!file.open(QIODevice::ReadOnly)) { + fprintf(stderr, "Could not open %s!\n", qPrintable(projectFile)); + return -1; + } + + if (compressedFile.isEmpty()) { + 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); + QDir parentDir = fi.dir(); + if (!parentDir.exists()) { + if (!parentDir.mkpath(QLatin1String("."))) { + fprintf(stderr, "Could not create output directory: %s\n", + qPrintable(parentDir.path())); + } + } + } + + QHelpProjectData *helpData = new QHelpProjectData(); + if (!helpData->readData(projectFile)) { + fprintf(stderr, "%s\n", qPrintable(helpData->errorMessage())); + return -1; + } + + QCoreApplication app(argc, argv); + HelpGenerator generator; + bool success = generator.generate(helpData, compressedFile); + delete helpData; + if (!success) { + fprintf(stderr, "%s\n", qPrintable(generator.error())); + return -1; + } + return 0; +} diff --git a/tools/assistant/tools/qhelpgenerator/qhelpgenerator.pro b/tools/assistant/tools/qhelpgenerator/qhelpgenerator.pro new file mode 100644 index 0000000..68efcf5 --- /dev/null +++ b/tools/assistant/tools/qhelpgenerator/qhelpgenerator.pro @@ -0,0 +1,14 @@ +TEMPLATE = app +TARGET = qhelpgenerator +DESTDIR = ../../../../bin +CONFIG += qt warn_on help console +CONFIG -= app_bundle +QT += network + +target.path=$$[QT_INSTALL_BINS] +INSTALLS += target + +SOURCES += ../shared/helpgenerator.cpp \ + main.cpp + +HEADERS += ../shared/helpgenerator.h diff --git a/tools/assistant/tools/shared/helpgenerator.cpp b/tools/assistant/tools/shared/helpgenerator.cpp new file mode 100644 index 0000000..a40cc4d --- /dev/null +++ b/tools/assistant/tools/shared/helpgenerator.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "helpgenerator.h" + +#include <private/qhelpgenerator_p.h> +#include <stdio.h> + +QT_BEGIN_NAMESPACE + +HelpGenerator::HelpGenerator() +{ + generator = new QHelpGenerator(this); + connect(generator, SIGNAL(statusChanged(const QString&)), + this, SLOT(printStatus(const QString&))); + connect(generator, SIGNAL(warning(const QString&)), + this, SLOT(printWarning(const QString&))); +} + +bool HelpGenerator::generate(QHelpDataInterface *helpData, + const QString &outputFileName) +{ + return generator->generate(helpData, outputFileName); +} + +QString HelpGenerator::error() const +{ + return generator->error(); +} + +void HelpGenerator::printStatus(const QString &msg) +{ + fprintf(stdout, "%s\n", qPrintable(msg)); +} + +void HelpGenerator::printWarning(const QString &msg) +{ + fprintf(stdout, "Warning: %s\n", qPrintable(msg)); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/shared/helpgenerator.h b/tools/assistant/tools/shared/helpgenerator.h new file mode 100644 index 0000000..ba8a479 --- /dev/null +++ b/tools/assistant/tools/shared/helpgenerator.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef HELPGENERATOR_H +#define HELPGENERATOR_H + +#include <QtCore/QObject> + +QT_BEGIN_NAMESPACE + +class QHelpDataInterface; +class QHelpGenerator; + +class HelpGenerator : public QObject +{ + Q_OBJECT + +public: + HelpGenerator(); + bool generate(QHelpDataInterface *helpData, + const QString &outputFileName); + QString error() const; + +private slots: + void printStatus(const QString &msg); + void printWarning(const QString &msg); + +private: + QHelpGenerator *generator; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/tools/tools.pro b/tools/assistant/tools/tools.pro new file mode 100644 index 0000000..8bb8cd7 --- /dev/null +++ b/tools/assistant/tools/tools.pro @@ -0,0 +1,8 @@ +TEMPLATE = subdirs +CONFIG += ordered + +SUBDIRS += assistant \ + qhelpgenerator \ + qcollectiongenerator \ + qhelpconverter + diff --git a/tools/assistant/translations/qt_help.pro b/tools/assistant/translations/qt_help.pro new file mode 100644 index 0000000..1684ac5 --- /dev/null +++ b/tools/assistant/translations/qt_help.pro @@ -0,0 +1,49 @@ +# Include those manually as they do not contain any directory specification + +SOURCES += ../lib/qhelpcollectionhandler.cpp \ + ../lib/qhelpcontentwidget.cpp \ + ../lib/qhelpdatainterface.cpp \ + ../lib/qhelpdbreader.cpp \ + ../lib/qhelpengine.cpp \ + ../lib/qhelpenginecore.cpp \ + ../lib/qhelpgenerator.cpp \ + ../lib/qhelpindexwidget.cpp \ + ../lib/qhelpprojectdata.cpp \ + ../lib/qhelpsearchengine.cpp \ + ../lib/qhelpsearchindexreader_clucene.cpp \ + ../lib/qhelpsearchindexreader_default.cpp \ + ../lib/qhelpsearchindexwriter_clucene.cpp \ + ../lib/qhelpsearchindexwriter_default.cpp \ + ../lib/qhelpsearchindex_default.cpp \ + ../lib/qhelpsearchquerywidget.cpp \ + ../lib/qhelpsearchresultwidget.cpp + +HEADERS += ../lib/qhelpcollectionhandler_p.h \ + ../lib/qhelpcontentwidget.h \ + ../lib/qhelpdatainterface_p.h \ + ../lib/qhelpdbreader_p.h \ + ../lib/qhelpengine.h \ + ../lib/qhelpenginecore.h \ + ../lib/qhelpengine_p.h \ + ../lib/qhelpgenerator_p.h \ + ../lib/qhelpindexwidget.h \ + ../lib/qhelpprojectdata_p.h \ + ../lib/qhelpsearchengine.h \ + ../lib/qhelpsearchindexreader_clucene_p.h \ + ../lib/qhelpsearchindexreader_default_p.h \ + ../lib/qhelpsearchindexwriter_clucene_p.h \ + ../lib/qhelpsearchindexwriter_default_p.h \ + ../lib/qhelpsearchindex_default_p.h \ + ../lib/qhelpsearchquerywidget.h \ + ../lib/qhelpsearchresultwidget.h \ + ../lib/qhelp_global.h + + +TRANSLATIONS=$$[QT_INSTALL_TRANSLATIONS]/qt_help_de.ts \ + $$[QT_INSTALL_TRANSLATIONS]/qt_help_ja.ts \ + $$[QT_INSTALL_TRANSLATIONS]/qt_help_pl.ts \ + $$[QT_INSTALL_TRANSLATIONS]/qt_help_untranslated.ts \ + $$[QT_INSTALL_TRANSLATIONS]/qt_help_tr_TR.ts \ + $$[QT_INSTALL_TRANSLATIONS]/qt_help_zh_CN.ts \ + $$[QT_INSTALL_TRANSLATIONS]/qt_help_zh_TW.ts +error("This is a dummy profile to be used for translations ONLY.") diff --git a/tools/assistant/translations/translations.pro b/tools/assistant/translations/translations.pro new file mode 100644 index 0000000..84bde8c --- /dev/null +++ b/tools/assistant/translations/translations.pro @@ -0,0 +1,49 @@ +# Include those manually as they do not contain any directory specification + +FORMS += ../tools/assistant/filternamedialog.ui \ + ../tools/assistant/installdialog.ui \ + ../tools/assistant/preferencesdialog.ui \ + ../tools/assistant/topicchooser.ui \ + ../tools/assistant/bookmarkdialog.ui + +SOURCES += ../tools/assistant/aboutdialog.cpp \ + ../tools/assistant/bookmarkmanager.cpp \ + ../tools/assistant/centralwidget.cpp \ + ../tools/assistant/cmdlineparser.cpp \ + ../tools/assistant/contentwindow.cpp \ + ../tools/assistant/filternamedialog.cpp \ + ../tools/assistant/helpviewer.cpp \ + ../tools/assistant/indexwindow.cpp \ + ../tools/assistant/installdialog.cpp \ + ../tools/assistant/main.cpp \ + ../tools/assistant/mainwindow.cpp \ + ../tools/assistant/preferencesdialog.cpp \ + ../tools/assistant/remotecontrol.cpp \ + ../tools/assistant/searchwidget.cpp \ + ../tools/assistant/topicchooser.cpp \ + +SOURCES += ../../shared/fontpanel/fontpanel.cpp + +HEADERS += ../tools/assistant/aboutdialog.h \ + ../tools/assistant/bookmarkmanager.h \ + ../tools/assistant/centralwidget.h \ + ../tools/assistant/cmdlineparser.h \ + ../tools/assistant/contentwindow.h \ + ../tools/assistant/filternamedialog.h \ + ../tools/assistant/helpviewer.h \ + ../tools/assistant/indexwindow.h \ + ../tools/assistant/installdialog.h \ + ../tools/assistant/mainwindow.h \ + ../tools/assistant/preferencesdialog.h \ + ../tools/assistant/remotecontrol.h \ + ../tools/assistant/remotecontrol_win.h \ + ../tools/assistant/searchwidget.h \ + ../tools/assistant/topicchooser.h \ + +TRANSLATIONS=$$[QT_INSTALL_TRANSLATIONS]/assistant_de.ts \ + $$[QT_INSTALL_TRANSLATIONS]/assistant_ja.ts \ + $$[QT_INSTALL_TRANSLATIONS]/assistant_pl.ts \ + $$[QT_INSTALL_TRANSLATIONS]/assistant_untranslated.ts \ + $$[QT_INSTALL_TRANSLATIONS]/assistant_tr_TR.ts \ + $$[QT_INSTALL_TRANSLATIONS]/assistant_zh_CN.ts \ + $$[QT_INSTALL_TRANSLATIONS]/assistant_zh_TW.ts diff --git a/tools/assistant/translations/translations_adp.pro b/tools/assistant/translations/translations_adp.pro new file mode 100644 index 0000000..f6ab62e --- /dev/null +++ b/tools/assistant/translations/translations_adp.pro @@ -0,0 +1,41 @@ +# 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 + + +TRANSLATIONS=$$[QT_INSTALL_TRANSLATIONS]/assistant_adp_de.ts \ + $$[QT_INSTALL_TRANSLATIONS]/assistant_adp_ja.ts \ + $$[QT_INSTALL_TRANSLATIONS]/assistant_adp_pl.ts \ + $$[QT_INSTALL_TRANSLATIONS]/assistant_adp_untranslated.ts \ + $$[QT_INSTALL_TRANSLATIONS]/assistant_adp_tr_TR.ts \ + $$[QT_INSTALL_TRANSLATIONS]/assistant_adp_zh_CN.ts \ + $$[QT_INSTALL_TRANSLATIONS]/assistant_adp_zh_TW.ts +error("This is a dummy profile to be used for translations ONLY.") |