diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:34:13 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:34:13 (GMT) |
commit | 67ad0519fd165acee4a4d2a94fa502e9e4847bd0 (patch) | |
tree | 1dbf50b3dff8d5ca7e9344733968c72704eb15ff /tools/assistant/compat | |
download | Qt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.zip Qt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.tar.gz Qt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.tar.bz2 |
Long live Qt!
Diffstat (limited to 'tools/assistant/compat')
71 files changed, 9100 insertions, 0 deletions
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 |