diff options
Diffstat (limited to 'tools/assistant/lib')
79 files changed, 15661 insertions, 0 deletions
diff --git a/tools/assistant/lib/fulltextsearch/fulltextsearch.pri b/tools/assistant/lib/fulltextsearch/fulltextsearch.pri new file mode 100644 index 0000000..134678f --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/fulltextsearch.pri @@ -0,0 +1,161 @@ +DEFINES += _BUILD_FOR_QT_ LUCENE_DISABLE_MEMTRACKING +win32:DEFINES += _CRT_SECURE_NO_DEPRECATE _MT + +CLUCENEDIR = ../../../../src/3rdparty/clucene/src/CLucene + +INCLUDEPATH += . .. \ + $$CLUCENEDIR \ + $$CLUCENEDIR/../ \ + $$CLUCENEDIR/analysis \ + $$CLUCENEDIR/analysis/standard \ + $$CLUCENEDIR/config \ + $$CLUCENEDIR/debug \ + $$CLUCENEDIR/document \ + $$CLUCENEDIR/index \ + $$CLUCENEDIR/queryParser \ + $$CLUCENEDIR/search \ + $$CLUCENEDIR/store \ + $$CLUCENEDIR/util + + +SOURCES += $$CLUCENEDIR/StdHeader.cpp \ + $$CLUCENEDIR/analysis/AnalysisHeader.cpp \ + $$CLUCENEDIR/analysis/Analyzers.cpp \ + $$CLUCENEDIR/config/gunichartables.cpp \ + $$CLUCENEDIR/config/repl_lltot.cpp \ + $$CLUCENEDIR/config/repl_tcscasecmp.cpp \ + $$CLUCENEDIR/config/repl_tcslwr.cpp \ + $$CLUCENEDIR/config/repl_tcstod.cpp \ + $$CLUCENEDIR/config/repl_tcstoll.cpp \ + $$CLUCENEDIR/config/repl_tprintf.cpp \ + $$CLUCENEDIR/config/threads.cpp \ + $$CLUCENEDIR/config/utf8.cpp \ + $$CLUCENEDIR/debug/condition.cpp \ + $$CLUCENEDIR/debug/error.cpp \ + $$CLUCENEDIR/debug/memtracking.cpp \ + $$CLUCENEDIR/document/DateField.cpp \ + $$CLUCENEDIR/document/Document.cpp \ + $$CLUCENEDIR/document/Field.cpp \ + $$CLUCENEDIR/index/CompoundFile.cpp \ + $$CLUCENEDIR/index/DocumentWriter.cpp \ + $$CLUCENEDIR/index/FieldInfos.cpp \ + $$CLUCENEDIR/index/FieldsReader.cpp \ + $$CLUCENEDIR/index/FieldsWriter.cpp \ + $$CLUCENEDIR/index/IndexModifier.cpp \ + $$CLUCENEDIR/index/IndexReader.cpp \ + $$CLUCENEDIR/index/IndexWriter.cpp \ + $$CLUCENEDIR/index/MultiReader.cpp \ + $$CLUCENEDIR/index/SegmentInfos.cpp \ + $$CLUCENEDIR/index/SegmentMergeInfo.cpp \ + $$CLUCENEDIR/index/SegmentMergeQueue.cpp \ + $$CLUCENEDIR/index/SegmentMerger.cpp \ + $$CLUCENEDIR/index/SegmentReader.cpp \ + $$CLUCENEDIR/index/SegmentTermDocs.cpp \ + $$CLUCENEDIR/index/SegmentTermEnum.cpp \ + $$CLUCENEDIR/index/SegmentTermPositions.cpp \ + $$CLUCENEDIR/index/SegmentTermVector.cpp \ + $$CLUCENEDIR/index/Term.cpp \ + $$CLUCENEDIR/index/TermInfo.cpp \ + $$CLUCENEDIR/index/TermInfosReader.cpp \ + $$CLUCENEDIR/index/TermInfosWriter.cpp \ + $$CLUCENEDIR/index/TermVectorReader.cpp \ + $$CLUCENEDIR/index/TermVectorWriter.cpp \ + $$CLUCENEDIR/queryParser/Lexer.cpp \ + $$CLUCENEDIR/queryParser/MultiFieldQueryParser.cpp \ + $$CLUCENEDIR/queryParser/QueryParser.cpp \ + $$CLUCENEDIR/queryParser/QueryParserBase.cpp \ + $$CLUCENEDIR/queryParser/QueryToken.cpp \ + $$CLUCENEDIR/queryParser/TokenList.cpp \ + $$CLUCENEDIR/search/BooleanQuery.cpp \ + $$CLUCENEDIR/search/BooleanScorer.cpp \ + $$CLUCENEDIR/search/CachingWrapperFilter.cpp \ + $$CLUCENEDIR/search/ChainedFilter.cpp \ + $$CLUCENEDIR/search/ConjunctionScorer.cpp \ + $$CLUCENEDIR/search/DateFilter.cpp \ + $$CLUCENEDIR/search/ExactPhraseScorer.cpp \ + $$CLUCENEDIR/search/Explanation.cpp \ + $$CLUCENEDIR/search/FieldCache.cpp \ + $$CLUCENEDIR/search/FieldCacheImpl.cpp \ + $$CLUCENEDIR/search/FieldDocSortedHitQueue.cpp \ + $$CLUCENEDIR/search/FieldSortedHitQueue.cpp \ + $$CLUCENEDIR/search/FilteredTermEnum.cpp \ + $$CLUCENEDIR/search/FuzzyQuery.cpp \ + $$CLUCENEDIR/search/HitQueue.cpp \ + $$CLUCENEDIR/search/Hits.cpp \ + $$CLUCENEDIR/search/IndexSearcher.cpp \ + $$CLUCENEDIR/search/MultiSearcher.cpp \ + $$CLUCENEDIR/search/MultiTermQuery.cpp \ + $$CLUCENEDIR/search/PhrasePositions.cpp \ + $$CLUCENEDIR/search/PhraseQuery.cpp \ + $$CLUCENEDIR/search/PhraseScorer.cpp \ + $$CLUCENEDIR/search/PrefixQuery.cpp \ + $$CLUCENEDIR/search/QueryFilter.cpp \ + $$CLUCENEDIR/search/RangeFilter.cpp \ + $$CLUCENEDIR/search/RangeQuery.cpp \ + $$CLUCENEDIR/search/SearchHeader.cpp \ + $$CLUCENEDIR/search/Similarity.cpp \ + $$CLUCENEDIR/search/SloppyPhraseScorer.cpp \ + $$CLUCENEDIR/search/Sort.cpp \ + $$CLUCENEDIR/search/TermQuery.cpp \ + $$CLUCENEDIR/search/TermScorer.cpp \ + $$CLUCENEDIR/search/WildcardQuery.cpp \ + $$CLUCENEDIR/search/WildcardTermEnum.cpp \ + $$CLUCENEDIR/store/FSDirectory.cpp \ + $$CLUCENEDIR/store/IndexInput.cpp \ + $$CLUCENEDIR/store/IndexOutput.cpp \ + $$CLUCENEDIR/store/Lock.cpp \ + $$CLUCENEDIR/store/MMapInput.cpp \ + $$CLUCENEDIR/store/RAMDirectory.cpp \ + $$CLUCENEDIR/store/TransactionalRAMDirectory.cpp \ + $$CLUCENEDIR/util/BitSet.cpp \ + $$CLUCENEDIR/util/Equators.cpp \ + $$CLUCENEDIR/util/FastCharStream.cpp \ + $$CLUCENEDIR/util/fileinputstream.cpp \ + $$CLUCENEDIR/util/Misc.cpp \ + $$CLUCENEDIR/util/Reader.cpp \ + $$CLUCENEDIR/util/StringBuffer.cpp \ + $$CLUCENEDIR/util/StringIntern.cpp \ + $$CLUCENEDIR/util/ThreadLocal.cpp \ + $$CLUCENEDIR/analysis/standard/StandardAnalyzer.cpp \ + $$CLUCENEDIR/analysis/standard/StandardFilter.cpp \ + $$CLUCENEDIR/analysis/standard/StandardTokenizer.cpp + + +#Header files +HEADERS += qclucene_global_p.h \ + qclucene-config_p.h \ + qanalyzer_p.h \ + qtokenizer_p.h \ + qtoken_p.h \ + qtokenstream_p.h \ + qdocument_p.h \ + qfield_p.h \ + qindexreader_p.h \ + qindexwriter_p.h \ + qterm_p.h \ + qqueryparser_p.h \ + qfilter_p.h \ + qhits_p.h \ + qsearchable_p.h \ + qsort_p.h \ + qquery_p.h \ + qreader_p.h + + +#Source files +SOURCES += qanalyzer.cpp \ + qtokenizer.cpp \ + qtoken.cpp \ + qtokenstream.cpp \ + qdocument.cpp \ + qfield.cpp \ + qindexreader.cpp \ + qindexwriter.cpp \ + qterm.cpp \ + qqueryparser.cpp \ + qfilter.cpp \ + qhits.cpp \ + qsearchable.cpp \ + qsort.cpp \ + qquery.cpp \ + qreader.cpp diff --git a/tools/assistant/lib/fulltextsearch/fulltextsearch.pro b/tools/assistant/lib/fulltextsearch/fulltextsearch.pro new file mode 100644 index 0000000..e0cd13a --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/fulltextsearch.pro @@ -0,0 +1,50 @@ + +QMAKE_TARGET_PRODUCT = QtCLucene +QMAKE_TARGET_DESCRIPTION = QtCLucene full text search library wrapper. +#if qt is built with frameworks in debug, we must build QtCLucene in debug and release +#that's a similar logic as in qbase.pri +mac:!static:contains(QT_CONFIG, qt_framework) { + CONFIG(debug, debug|release) { + !build_pass:CONFIG += build_all + } +} +QT_CONFIG -= qt_framework +QT -= gui +TEMPLATE = lib +TARGET = QtCLucene +DEFINES += QHELP_LIB +include(../../../../src/qbase.pri) +include(fulltextsearch.pri) + +CONFIG += qt warn_off +contains(QT_CONFIG, reduce_exports) { + CONFIG += hide_symbols + # workaround for compiler errors on Ubuntu + linux*-g++*:DEFINES += _GLIBCXX_EXTERN_TEMPLATE=0 +} + +unix:QMAKE_PKGCONFIG_REQUIRES = QtCore + +# impossible to disable exceptions in clucene atm +CONFIG(exceptions_off) { + CONFIG -= exceptions_off + CONFIG += exceptions + !win32|win32-g++ { + QMAKE_CFLAGS -= -fno-exceptions + QMAKE_CXXFLAGS -= -fno-exceptions + QMAKE_LFLAGS -= -fno-exceptions + QMAKE_CFLAGS += -fexceptions + QMAKE_CXXFLAGS += -fexceptions + QMAKE_LFLAGS += -fexceptions + } +} + +win32-msvc.net | win32-msvc2* { + QMAKE_CFLAGS_RELEASE -= -O2 + QMAKE_CXXFLAGS_RELEASE -= -O2 +} + +# the following define could be set globally in case we need it elsewhere +solaris* { + DEFINES += Q_SOLARIS_VERSION=$$system(uname -r | sed -e 's/5\.//') +} diff --git a/tools/assistant/lib/fulltextsearch/license.txt b/tools/assistant/lib/fulltextsearch/license.txt new file mode 100644 index 0000000..9ef3d70 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/license.txt @@ -0,0 +1,503 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + diff --git a/tools/assistant/lib/fulltextsearch/qanalyzer.cpp b/tools/assistant/lib/fulltextsearch/qanalyzer.cpp new file mode 100644 index 0000000..e19a075 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qanalyzer.cpp @@ -0,0 +1,201 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qanalyzer_p.h" +#include "qclucene_global_p.h" + +#include <CLucene.h> +#include <CLucene/analysis/AnalysisHeader.h> + +QT_BEGIN_NAMESPACE + +QCLuceneAnalyzerPrivate::QCLuceneAnalyzerPrivate() + : QSharedData() +{ + analyzer = 0; + deleteCLuceneAnalyzer = true; +} + +QCLuceneAnalyzerPrivate::QCLuceneAnalyzerPrivate(const QCLuceneAnalyzerPrivate &other) + : QSharedData() +{ + analyzer = _CL_POINTER(other.analyzer); +} + +QCLuceneAnalyzerPrivate::~QCLuceneAnalyzerPrivate() +{ + if (deleteCLuceneAnalyzer) + _CLDECDELETE(analyzer); +} + + +QCLuceneAnalyzer::QCLuceneAnalyzer() + : d(new QCLuceneAnalyzerPrivate()) +{ + //nothing todo, private +} + +QCLuceneAnalyzer::~QCLuceneAnalyzer() +{ + // nothing todo +} + +qint32 QCLuceneAnalyzer::positionIncrementGap(const QString &fieldName) const +{ + Q_UNUSED(fieldName); + return 0; +} + +QCLuceneTokenStream QCLuceneAnalyzer::tokenStream(const QString &fieldName, + const QCLuceneReader &reader) const +{ + TCHAR *fName = QStringToTChar(fieldName); + QCLuceneTokenStream tokenStream; + tokenStream.d->tokenStream = d->analyzer->tokenStream(fName, reader.d->reader); + delete [] fName; + + return tokenStream; +} + + +QCLuceneStandardAnalyzer::QCLuceneStandardAnalyzer() + : QCLuceneAnalyzer() +{ + d->analyzer = new lucene::analysis::standard::StandardAnalyzer(); +} + +QCLuceneStandardAnalyzer::~QCLuceneStandardAnalyzer() +{ + // nothing todo +} + +QCLuceneStandardAnalyzer::QCLuceneStandardAnalyzer(const QStringList &stopWords) +{ + const TCHAR **tArray = new const TCHAR*[stopWords.count() +1]; + + for(int i = 0; i < stopWords.count(); ++i) { + TCHAR *stopWord = QStringToTChar(stopWords.at(i)); + tArray[i] = STRDUP_TtoT(stopWord); + delete [] stopWord; + } + tArray[stopWords.count()] = 0; + + d->analyzer = new lucene::analysis::standard::StandardAnalyzer(tArray); +} + + +QCLuceneWhitespaceAnalyzer::QCLuceneWhitespaceAnalyzer() + : QCLuceneAnalyzer() +{ + d->analyzer = new lucene::analysis::WhitespaceAnalyzer(); +} + +QCLuceneWhitespaceAnalyzer::~QCLuceneWhitespaceAnalyzer() +{ + // nothing todo +} + + +QCLuceneSimpleAnalyzer::QCLuceneSimpleAnalyzer() + : QCLuceneAnalyzer() +{ + d->analyzer = new lucene::analysis::SimpleAnalyzer(); +} + +QCLuceneSimpleAnalyzer::~QCLuceneSimpleAnalyzer() +{ + // nothing todo +} + + +QCLuceneStopAnalyzer::QCLuceneStopAnalyzer() + : QCLuceneAnalyzer() +{ + d->analyzer = new lucene::analysis::StopAnalyzer(); +} + +QCLuceneStopAnalyzer::~QCLuceneStopAnalyzer() +{ + // nothing todo +} + +QCLuceneStopAnalyzer::QCLuceneStopAnalyzer(const QStringList &stopWords) + : QCLuceneAnalyzer() +{ + const TCHAR **tArray = new const TCHAR*[stopWords.count() +1]; + + for(int i = 0; i < stopWords.count(); ++i) { + TCHAR *stopWord = QStringToTChar(stopWords.at(i)); + tArray[i] = STRDUP_TtoT(stopWord); + delete [] stopWord; + } + tArray[stopWords.count()] = 0; + + d->analyzer = new lucene::analysis::StopAnalyzer(tArray); +} + +QStringList QCLuceneStopAnalyzer::englishStopWords() const +{ + QStringList stopWordList; + + const TCHAR** stopWords = lucene::analysis::StopAnalyzer::ENGLISH_STOP_WORDS; + for (qint32 i = 0; stopWords[i] != 0; ++i) + stopWordList.append(TCharToQString(stopWords[i])); + + return stopWordList; +} + + +QCLuceneKeywordAnalyzer::QCLuceneKeywordAnalyzer() + : QCLuceneAnalyzer() +{ + d->analyzer = new lucene::analysis::KeywordAnalyzer(); +} + +QCLuceneKeywordAnalyzer::~QCLuceneKeywordAnalyzer() +{ + // nothing todo +} + + +QCLucenePerFieldAnalyzerWrapper::QCLucenePerFieldAnalyzerWrapper( + QCLuceneAnalyzer *defaultAnalyzer) + : QCLuceneAnalyzer() +{ + d->analyzer = new + lucene::analysis::PerFieldAnalyzerWrapper(defaultAnalyzer->d->analyzer); + + analyzers.append(defaultAnalyzer); + defaultAnalyzer->d->deleteCLuceneAnalyzer = false; +} + +QCLucenePerFieldAnalyzerWrapper::~QCLucenePerFieldAnalyzerWrapper() +{ + qDeleteAll(analyzers); +} + +void QCLucenePerFieldAnalyzerWrapper::addAnalyzer(const QString &fieldName, + QCLuceneAnalyzer *analyzer) +{ + lucene::analysis::PerFieldAnalyzerWrapper *analyzerWrapper = + static_cast<lucene::analysis::PerFieldAnalyzerWrapper*> (d->analyzer); + + if (analyzerWrapper == 0) + return; + + analyzers.append(analyzer); + analyzer->d->deleteCLuceneAnalyzer = false; + + TCHAR *fName = QStringToTChar(fieldName); + analyzerWrapper->addAnalyzer(fName, analyzer->d->analyzer); + delete [] fName; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qanalyzer_p.h b/tools/assistant/lib/fulltextsearch/qanalyzer_p.h new file mode 100644 index 0000000..c0b94f4 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qanalyzer_p.h @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QANALYZER_P_H +#define QANALYZER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qreader_p.h" +#include "qtokenstream_p.h" +#include "qclucene_global_p.h" + +#include <QtCore/QList> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(analysis) + class Analyzer; +CL_NS_END +CL_NS_USE(analysis) + +QT_BEGIN_NAMESPACE + +class QCLuceneIndexWriter; +class QCLuceneQueryParser; +class QCLuceneStopAnalyzer; +class QCLuceneSimpleAnalyzer; +class QCLuceneKeywordAnalyzer; +class QCLuceneStandardAnalyzer; +class QCLuceneWhitespaceAnalyzer; +class QCLucenePerFieldAnalyzerWrapper; + +class QHELP_EXPORT QCLuceneAnalyzerPrivate : public QSharedData +{ +public: + QCLuceneAnalyzerPrivate(); + QCLuceneAnalyzerPrivate(const QCLuceneAnalyzerPrivate &other); + + ~QCLuceneAnalyzerPrivate(); + + Analyzer *analyzer; + bool deleteCLuceneAnalyzer; + +private: + QCLuceneAnalyzerPrivate &operator=(const QCLuceneAnalyzerPrivate &other); +}; + +class QHELP_EXPORT QCLuceneAnalyzer +{ +public: + virtual ~QCLuceneAnalyzer(); + + qint32 positionIncrementGap(const QString &fieldName) const; + QCLuceneTokenStream tokenStream(const QString &fieldName, + const QCLuceneReader &reader) const; + +protected: + friend class QCLuceneIndexWriter; + friend class QCLuceneQueryParser; + friend class QCLuceneStopAnalyzer; + friend class QCLuceneSimpleAnalyzer; + friend class QCLuceneKeywordAnalyzer; + friend class QCLuceneStandardAnalyzer; + friend class QCLuceneWhitespaceAnalyzer; + friend class QCLucenePerFieldAnalyzerWrapper; + QSharedDataPointer<QCLuceneAnalyzerPrivate> d; + +private: + QCLuceneAnalyzer(); +}; + +class QHELP_EXPORT QCLuceneStandardAnalyzer : public QCLuceneAnalyzer +{ +public: + QCLuceneStandardAnalyzer(); + QCLuceneStandardAnalyzer(const QStringList &stopWords); + + ~QCLuceneStandardAnalyzer(); +}; + +class QHELP_EXPORT QCLuceneWhitespaceAnalyzer : public QCLuceneAnalyzer +{ +public: + QCLuceneWhitespaceAnalyzer(); + ~QCLuceneWhitespaceAnalyzer(); +}; + +class QHELP_EXPORT QCLuceneSimpleAnalyzer : public QCLuceneAnalyzer +{ +public: + QCLuceneSimpleAnalyzer(); + ~QCLuceneSimpleAnalyzer(); +}; + +class QHELP_EXPORT QCLuceneStopAnalyzer : public QCLuceneAnalyzer +{ +public: + QCLuceneStopAnalyzer(); + QCLuceneStopAnalyzer(const QStringList &stopWords); + + ~QCLuceneStopAnalyzer(); + + QStringList englishStopWords() const; +}; + +class QHELP_EXPORT QCLuceneKeywordAnalyzer : public QCLuceneAnalyzer +{ +public: + QCLuceneKeywordAnalyzer(); + ~QCLuceneKeywordAnalyzer(); +}; + +class QHELP_EXPORT QCLucenePerFieldAnalyzerWrapper : public QCLuceneAnalyzer +{ +public: + QCLucenePerFieldAnalyzerWrapper(QCLuceneAnalyzer *defaultAnalyzer); + ~QCLucenePerFieldAnalyzerWrapper(); + + void addAnalyzer(const QString &fieldName, QCLuceneAnalyzer *analyzer); + +private: + QList<QCLuceneAnalyzer*> analyzers; +}; + +QT_END_NAMESPACE + +#endif // QANALYZER_P_H diff --git a/tools/assistant/lib/fulltextsearch/qclucene-config_p.h b/tools/assistant/lib/fulltextsearch/qclucene-config_p.h new file mode 100644 index 0000000..b3befbe --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qclucene-config_p.h @@ -0,0 +1,552 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QCLUCENE_CONFIG_P_H +#define QCLUCENE_CONFIG_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> + +#ifndef _SRC_CLUCENE_CLUCENE_CONFIG_H +#define _SRC_CLUCENE_CLUCENE_CONFIG_H 1 + +/* +src/CLucene/clucene-config.h. +Generated +automatically +at +end +of +configure. +*/ +/* config.h.tmp. Generated by configure. */ +/* config.h.tmp.in. Generated from configure.ac by autoheader. */ + +/* Disable multithreading */ +/* #undef _CL_DISABLE_MULTITHREADING */ + +/* Define to 1 if you have the <algorithm> header file. */ +#ifndef _CL_HAVE_ALGORITHM +#define _CL_HAVE_ALGORITHM 1 +#endif + +/* Define to 1 if you have the <ctype.h> header file. */ +#ifndef _CL_HAVE_CTYPE_H +#define _CL_HAVE_CTYPE_H 1 +#endif + +/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'. + */ +#ifndef _CL_HAVE_DIRENT_H +#define _CL_HAVE_DIRENT_H 1 +#endif + +#if !defined (__MINGW32__) + /* Define to 1 if you have the <dlfcn.h> header file. */ +# ifndef _CL_HAVE_DLFCN_H +# define _CL_HAVE_DLFCN_H 1 +# endif +#endif + +/* Define to 1 if you have the <errno.h> header file. */ +#ifndef _CL_HAVE_ERRNO_H +#define _CL_HAVE_ERRNO_H 1 +#endif + +#if !defined(__SUNPRO_CC) && !defined(__SUNPRO_C) + /* Define to 1 if you have the <ext/hash_map> header file. */ +# ifndef _CL_HAVE_EXT_HASH_MAP +# define _CL_HAVE_EXT_HASH_MAP 1 +# endif + + /* Define to 1 if you have the <ext/hash_set> header file. */ +# ifndef _CL_HAVE_EXT_HASH_SET +# define _CL_HAVE_EXT_HASH_SET 1 +# endif +#endif + +/* Define to 1 if you have the <fcntl.h> header file. */ +#ifndef _CL_HAVE_FCNTL_H +#define _CL_HAVE_FCNTL_H 1 +#endif + +#if !defined(__xlC__) && !defined(__xlc__) && !defined (__MINGW32__) && \ + !defined(__HP_aCC) && !defined(__SUNPRO_C) && !defined(__SUNPRO_CC) || \ + defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x550) || (defined(__HP_aCC) && defined(__ia64)) + /* Define to 1 if the system has the type `float_t'. */ +# ifndef _CL_HAVE_FLOAT_T +# define _CL_HAVE_FLOAT_T 1 +# endif +#endif + +/* Define to 1 if you have the <functional> header file. */ +#ifndef _CL_HAVE_FUNCTIONAL +#define _CL_HAVE_FUNCTIONAL 1 +#endif + +/* Does not support new float byte<->float conversions */ +#ifndef _CL_HAVE_FUNCTIONING_FLOAT_BYTE +#define _CL_HAVE_FUNCTIONING_FLOAT_BYTE +#endif + +/* Define to 1 if you have the `getpagesize' function. */ +#ifndef _CL_HAVE_GETPAGESIZE +#define _CL_HAVE_GETPAGESIZE 1 +#endif + +/* Define to 1 if you have the <hash_map> header file. */ +/* #undef _CL_HAVE_HASH_MAP */ + +/* Define to 1 if you have the <hash_set> header file. */ +/* #undef _CL_HAVE_HASH_SET */ + +/* Define to 1 if the system has the type `intptr_t'. */ +#ifndef _CL_HAVE_INTPTR_T +#define _CL_HAVE_INTPTR_T 1 +#endif + +/* Define to 1 if you have the <inttypes.h> header file. */ +#ifndef _CL_HAVE_INTTYPES_H +#define _CL_HAVE_INTTYPES_H 1 +#endif + +/* Define to 1 if you have the <list> header file. */ +#ifndef _CL_HAVE_LIST +#define _CL_HAVE_LIST 1 +#endif + +/* Define to 1 if you have the `lltoa' function. */ +/* #undef _CL_HAVE_LLTOA */ + +#if defined(__MINGW32__) + /* Define to 1 if you have the `lltow' function. */ +# ifndef _CL_HAVE_LLTOW +# define _CL_HAVE_LLTOW 1 +# endif +#endif + +#if !defined(__SUNPRO_CC) && !defined(__SUNPRO_C) && !defined(__xlC__) && !defined(__xlc__) + /* Define to 1 if long double works and has more range or precision than double. */ +# ifndef _CL_HAVE_LONG_DOUBLE +# define _CL_HAVE_LONG_DOUBLE 1 +# endif +#endif + +/* Define to 1 if you have the <map> header file. */ +#ifndef _CL_HAVE_MAP +#define _CL_HAVE_MAP 1 +#endif + +/* Define to 1 if you have the <math.h> header file. */ +#ifndef _CL_HAVE_MATH_H +#define _CL_HAVE_MATH_H 1 +#endif + +/* Define to 1 if you have the <memory.h> header file. */ +#ifndef _CL_HAVE_MEMORY_H +#define _CL_HAVE_MEMORY_H 1 +#endif + +#if !defined(__MINGW32__) && !defined(__HP_aCC) && !defined(__xlC__) && !defined(__xlc__) + /* Define to 1 if you have a working `mmap' system call. */ +# ifndef _CL_HAVE_MMAP +# define _CL_HAVE_MMAP 1 +# endif +#endif + +/* define if the compiler implements namespaces */ +#ifndef _CL_HAVE_NAMESPACES +#define _CL_HAVE_NAMESPACES +#endif + +#if defined(__SUNPRO_CC) || defined(__SUNPRO_C) || defined(__HP_aCC) || defined(__xlC__) || defined(__xlc__) + /* Define if you have the nanosleep function */ +# ifndef _CL_HAVE_NANOSLEEP +# define _CL_HAVE_NANOSLEEP 1 +# endif +#endif + +/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */ +/* #undef _CL_HAVE_NDIR_H */ + +/* Does not support new float byte<->float conversions */ +/* #undef _CL_HAVE_NO_FLOAT_BYTE */ + +/* Does not support try/catch blocks */ +/* #undef _CL_HAVE_NO_FUNCTION_TRY_BLOCKS */ + +/* Define to 1 if you have the `printf' function. */ +#ifndef _CL_HAVE_PRINTF +#define _CL_HAVE_PRINTF 1 +#endif + +#if !defined(__MINGW32__) + /* Define if you have POSIX threads libraries and header files. */ +# ifndef _CL_HAVE_PTHREAD +# define _CL_HAVE_PTHREAD 1 +# endif +#endif + +/* Define if recursive pthread mutexes are available */ +/* #undef _CL_HAVE_PTHREAD_MUTEX_RECURSIVE */ + +/* Define to 1 if you have the <set> header file. */ +#ifndef _CL_HAVE_SET +#define _CL_HAVE_SET 1 +#endif + +/* Define to 1 if you have the `snprintf' function. */ +#ifndef _CL_HAVE_SNPRINTF +#define _CL_HAVE_SNPRINTF 1 +#endif + +/* Defined if the snprintf overflow test fails */ +/* #undef _CL_HAVE_SNPRINTF_BUG */ + +/* Define to 1 if you have the `snwprintf' function. */ +/* #undef _CL_HAVE_SNWPRINTF */ + +#if !defined(__HP_aCC) && !defined(__SUNPRO_CC) && !defined(__SUNPRO_C) + /* define if the compiler supports ISO C++ standard library */ +# ifndef _CL_HAVE_STD +# define _CL_HAVE_STD +# endif +#endif + +/* Define to 1 if you have the <stdarg.h> header file. */ +#ifndef _CL_HAVE_STDARG_H +#define _CL_HAVE_STDARG_H 1 +#endif + +/* x */ +#ifndef _CL_HAVE_STDEXCEPT +#define _CL_HAVE_STDEXCEPT +#endif + +#if !defined(__SUNPRO_CC) && !defined(__SUNPRO_C) && !defined(__HP_aCC) && \ + !defined(__xlC__) && !defined(__xlc__) + /* Define to 1 if you have the <stdint.h> header file. */ +# ifndef _CL_HAVE_STDINT_H +# define _CL_HAVE_STDINT_H 1 +# endif +#endif + +#if !defined(__HP_aCC) + /* Define to 1 if you have the <stdlib.h> header file. */ +# ifndef _CL_HAVE_STDLIB_H +# define _CL_HAVE_STDLIB_H 1 +# endif + + /* define if the compiler supports Standard Template Library */ +# ifndef _CL_HAVE_STL +# define _CL_HAVE_STL +# endif +#endif + +/* Define to 1 if you have the <strings.h> header file. */ +#ifndef _CL_HAVE_STRINGS_H +#define _CL_HAVE_STRINGS_H 1 +#endif + +/* Define to 1 if you have the <string.h> header file. */ +#ifndef _CL_HAVE_STRING_H +#define _CL_HAVE_STRING_H 1 +#endif + +/* Define to 1 if you have the `strlwr' function. */ +/* #undef _CL_HAVE_STRLWR */ + +/* Define to 1 if you have the `strtoll' function. */ +/* #undef _CL_HAVE_STRTOLL */ + +/* Define to 1 if you have the `strupr' function. */ +/* #undef _CL_HAVE_STRUPR */ + +/* Defined if the swprintf test fails */ +#ifndef _CL_HAVE_SWPRINTF_BUG +#define _CL_HAVE_SWPRINTF_BUG +#endif + +/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'. + */ +/* #undef _CL_HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'. + */ +/* #undef _CL_HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#ifndef _CL_HAVE_SYS_STAT_H +#define _CL_HAVE_SYS_STAT_H 1 +#endif + +/* Define to 1 if you have the <sys/timeb.h> header file. */ +#ifndef _CL_HAVE_SYS_TIMEB_H +#define _CL_HAVE_SYS_TIMEB_H 1 +#endif + +/* Define to 1 if you have the <sys/types.h> header file. */ +#ifndef _CL_HAVE_SYS_TYPES_H +#define _CL_HAVE_SYS_TYPES_H 1 +#endif + +// Do not use the tchar.h that ships with mingw, this causes the qt build to +// fail (211547, 211401, etc...), reuse the replacement as with any other compiler +// #if defined(__MINGW32__) +// /* Define to 1 if you have the <tchar.h> header file. */ +// # ifndef _CL_HAVE_TCHAR_H +// # define _CL_HAVE_TCHAR_H 1 +// # endif +// #endif + +#if defined(__MINGW32__) || defined(__SUNPRO_CC) || defined(__SUNPRO_C) + /* Define to 1 if you have the `tell' function. */ +# ifndef _CL_HAVE_TELL +# define _CL_HAVE_TELL 1 +# endif +#endif + +/* Define to 1 if you have the <unistd.h> header file. */ +#ifndef _CL_HAVE_UNISTD_H +#define _CL_HAVE_UNISTD_H 1 +#endif + +/* Define to 1 if you have the <vector> header file. */ +#ifndef _CL_HAVE_VECTOR +#define _CL_HAVE_VECTOR 1 +#endif + +/* Define to 1 if you have the `vsnwprintf' function. */ +/* #undef _CL_HAVE_VSNWPRINTF */ + +/* Define to 1 if you have the <wchar.h> header file. */ +#ifndef _CL_HAVE_WCHAR_H +#define _CL_HAVE_WCHAR_H 1 +#endif + +/* Define to 1 if the system has the type `wchar_t'. */ +#ifndef _CL_HAVE_WCHAR_T +#define _CL_HAVE_WCHAR_T 1 +#endif + +#if !defined(__SUNPRO_CC) && !defined(__SUNPRO_C) && !defined(__MINGW32__) && \ + !defined(Q_OS_MAC) && !defined(__HP_aCC) + /* Define to 1 if you have the `wcscasecmp' function. */ +# ifndef _CL_HAVE_WCSCASECMP +# define _CL_HAVE_WCSCASECMP 1 +# endif +#endif + +/* Define to 1 if you have the `wcscat' function. */ +#ifndef _CL_HAVE_WCSCAT +#define _CL_HAVE_WCSCAT 1 +#endif + +/* Define to 1 if you have the `wcschr' function. */ +#ifndef _CL_HAVE_WCSCHR +#define _CL_HAVE_WCSCHR 1 +#endif + +/* Define to 1 if you have the `wcscmp' function. */ +#ifndef _CL_HAVE_WCSCMP +#define _CL_HAVE_WCSCMP 1 +#endif + +/* Define to 1 if you have the `wcscpy' function. */ +#ifndef _CL_HAVE_WCSCPY +#define _CL_HAVE_WCSCPY 1 +#endif + +/* Define to 1 if you have the `wcscspn' function. */ +#ifndef _CL_HAVE_WCSCSPN +#define _CL_HAVE_WCSCSPN 1 +#endif + +#if defined(__MINGW32__) + /* Define to 1 if you have the `wcsicmp' function. */ +# ifndef _CL_HAVE_WCSICMP +# define _CL_HAVE_WCSICMP 1 +# endif +#endif + +/* Define to 1 if you have the `wcslen' function. */ +#ifndef _CL_HAVE_WCSLEN +#define _CL_HAVE_WCSLEN 1 +#endif + +/* Define to 1 if you have the `wcsncmp' function. */ +#ifndef _CL_HAVE_WCSNCMP +#define _CL_HAVE_WCSNCMP 1 +#endif + +/* Define to 1 if you have the `wcsncpy' function. */ +#ifndef _CL_HAVE_WCSNCPY +#define _CL_HAVE_WCSNCPY 1 +#endif + +/* Define to 1 if you have the `wcsstr' function. */ +#ifndef _CL_HAVE_WCSSTR +#define _CL_HAVE_WCSSTR 1 +#endif + +/* Define to 1 if you have the `wcstod' function. */ +#ifndef _CL_HAVE_WCSTOD +#define _CL_HAVE_WCSTOD 1 +#endif + +#if !defined(__SUNPRO_CC) && !defined(__SUNPRO_C) && !defined(__HP_aCC) + /* Define to 1 if you have the `wcstoll' function. */ +# ifndef _CL_HAVE_WCSTOLL +# define _CL_HAVE_WCSTOLL 1 +# endif +#endif + +#if defined(__MINGW32__) + /* Define to 1 if you have the `wcsupr' function. */ +# ifndef _CL_HAVE_WCSUPR +# define _CL_HAVE_WCSUPR 1 +# endif +#endif + +#if defined(__SUNPRO_CC) || defined(__SUNPRO_C) || defined(__HP_aCC) + /* Define to 1 if you have a functioning <wchar.h> header file. */ +# ifndef _CL_HAVE_WCTYPE_H +# define _CL_HAVE_WCTYPE_H +# endif +#endif + +/* Define to 1 if you have the `wprintf' function. */ +/* #undef _CL_HAVE_WPRINTF */ + +#if defined(__MINGW32__) + /* Define to 1 if you have the `_filelength' function. */ +# ifndef _CL_HAVE__FILELENGTH +# define _CL_HAVE__FILELENGTH 1 +# endif +#endif + +/* How to define a static const in a class */ +#ifndef LUCENE_STATIC_CONSTANT_SYNTAX +#define LUCENE_STATIC_CONSTANT_SYNTAX 1 +#endif + +/* Name of package */ +#ifndef _CL_PACKAGE +#define _CL_PACKAGE "clucene-core" +#endif + +/* Define to the address where bug reports for this package should be sent. */ +#ifndef _CL_PACKAGE_BUGREPORT +#define _CL_PACKAGE_BUGREPORT "" +#endif + +/* Define to the full name of this package. */ +#ifndef _CL_PACKAGE_NAME +#define _CL_PACKAGE_NAME "" +#endif + +/* Define to the full name and version of this package. */ +#ifndef _CL_PACKAGE_STRING +#define _CL_PACKAGE_STRING "" +#endif + +/* Define to the one symbol short name of this package. */ +#ifndef _CL_PACKAGE_TARNAME +#define _CL_PACKAGE_TARNAME "" +#endif + +/* Define to the version of this package. */ +#ifndef _CL_PACKAGE_VERSION +#define _CL_PACKAGE_VERSION "" +#endif + +/* Define to the necessary symbol if this constant uses a non-standard name on + your system. */ +/* #undef _CL_PTHREAD_CREATE_JOINABLE */ + +/* The size of a `unsigned char', as computed by sizeof. */ +/* #undef _CL_SIZEOF_UNSIGNED_CHAR */ + +/* The size of a `unsigned int', as computed by sizeof. */ +/* #undef _CL_SIZEOF_UNSIGNED_INT */ + +/* The size of a `unsigned long', as computed by sizeof. */ +/* #undef _CL_SIZEOF_UNSIGNED_LONG */ + +/* The size of a `unsigned long long', as computed by sizeof. */ +/* #undef _CL_SIZEOF_UNSIGNED_LONG_LONG */ + +/* The size of a `unsigned __int64', as computed by sizeof. */ +/* #undef _CL_SIZEOF_UNSIGNED___INT64 */ + +/* Define to 1 if the `S_IS*' macros in <sys/stat.h> do not work properly. */ +/* #undef _CL_STAT_MACROS_BROKEN */ + +#if !defined(__HP_aCC) + /* Define to 1 if you have the ANSI C header files. */ +# ifndef _CL_STDC_HEADERS +# define _CL_STDC_HEADERS 1 +# endif + +/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */ +# ifndef _CL_TIME_WITH_SYS_TIME +# define _CL_TIME_WITH_SYS_TIME 1 +# endif +#endif + +/* Version number of package */ +#ifndef _CL_VERSION +#define _CL_VERSION "0.9.17" +#endif + +/* Forces into Ascii mode */ +/* #undef _ASCII */ + +/* Conditional Debugging */ +/* #undef _CL__CND_DEBUG */ + +/* debuging option */ +/* #undef _DEBUG */ + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* If not already defined, then define as a datatype of *exactly* 32 bits. */ +/* #undef uint32_t */ + +/* If not already defined, then define as a datatype of *exactly* 64 bits. */ +/* #undef uint64_t */ + +/* If not already defined, then define as a datatype of *exactly* 8 bits. */ +/* #undef uint8_t */ + +/* once: +_SRC_CLUCENE_CLUCENE_CONFIG_H +*/ +#endif + + +#if defined Q_CC_MSVC && _MSC_VER < 1300 +# define LUCENE_NO_STDC_NAMESPACE +#endif + + +#endif // QCLUCENE_CONFIG_P_H + diff --git a/tools/assistant/lib/fulltextsearch/qclucene_global_p.h b/tools/assistant/lib/fulltextsearch/qclucene_global_p.h new file mode 100644 index 0000000..2a9d146 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qclucene_global_p.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QCLUCENE_GLOBAL_P_H +#define QCLUCENE_GLOBAL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#if !defined(_MSC_VER) +# include "qclucene-config_p.h" +#endif + +#include <QtCore/QChar> +#include <QtCore/QString> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +#if !defined(QT_SHARED) && !defined(QT_DLL) +# define QHELP_EXPORT +#elif defined(QHELP_LIB) +# define QHELP_EXPORT Q_DECL_EXPORT +#else +# define QHELP_EXPORT Q_DECL_IMPORT +#endif + +// +// W A R N I N G +// ------------- +// +// adjustments here, need to be done in +// QTDIR/src/3rdparty/clucene/src/CLucene/StdHeader.h as well +// +#if defined(_LUCENE_DONTIMPLEMENT_NS_MACROS) + +#elif !defined(DISABLE_NAMESPACE) +# ifdef QT_NAMESPACE +# define CL_NS_DEF(sub) namespace QT_NAMESPACE { namespace lucene{ namespace sub{ +# define CL_NS_DEF2(sub,sub2) namespace QT_NAMESPACE { namespace lucene{ namespace sub{ namespace sub2 { + +# define CL_NS_END }}} +# define CL_NS_END2 }}}} + +# define CL_NS_USE(sub) using namespace QT_NAMESPACE::lucene::sub; +# define CL_NS_USE2(sub,sub2) using namespace QT_NAMESPACE::lucene::sub::sub2; + +# define CL_NS(sub) QT_NAMESPACE::lucene::sub +# define CL_NS2(sub,sub2) QT_NAMESPACE::lucene::sub::sub2 +# else +# define CL_NS_DEF(sub) namespace lucene{ namespace sub{ +# define CL_NS_DEF2(sub,sub2) namespace lucene{ namespace sub{ namespace sub2 { + +# define CL_NS_END }} +# define CL_NS_END2 }}} + +# define CL_NS_USE(sub) using namespace lucene::sub; +# define CL_NS_USE2(sub,sub2) using namespace lucene::sub::sub2; + +# define CL_NS(sub) lucene::sub +# define CL_NS2(sub,sub2) lucene::sub::sub2 +# endif +#else +# define CL_NS_DEF(sub) +# define CL_NS_DEF2(sub, sub2) +# define CL_NS_END +# define CL_NS_END2 +# define CL_NS_USE(sub) +# define CL_NS_USE2(sub,sub2) +# define CL_NS(sub) +# define CL_NS2(sub,sub2) +#endif + +#if !defined(_MSC_VER) && defined(_CL_HAVE_WCHAR_H) && defined(_CL_HAVE_WCHAR_T) +# if !defined(TCHAR) +# define TCHAR wchar_t +# endif +#else +# include <windows.h> +#endif + +namespace { + TCHAR* QStringToTChar(const QString &str) + { + TCHAR *string = new TCHAR[(str.length() +1) * sizeof(TCHAR)]; + memset(string, 0, (str.length() +1) * sizeof(TCHAR)); + #if defined(UNICODE) || defined(_CL_HAVE_WCHAR_H) && defined(_CL_HAVE_WCHAR_T) + str.toWCharArray(string); + #else + const QByteArray ba = str.toAscii(); + strcpy(string, ba.constData()); + #endif + return string; + } + + QString TCharToQString(const TCHAR *string) + { + #if defined(UNICODE) || defined(_CL_HAVE_WCHAR_H) && defined(_CL_HAVE_WCHAR_T) + QString retValue = QString::fromWCharArray(string); + return retValue; + #else + return QString(QLatin1String(string)); + #endif + } +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QCLUCENE_GLOBAL_P_H diff --git a/tools/assistant/lib/fulltextsearch/qdocument.cpp b/tools/assistant/lib/fulltextsearch/qdocument.cpp new file mode 100644 index 0000000..7e0f6d9 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qdocument.cpp @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qdocument_p.h" +#include "qreader_p.h" +#include "qclucene_global_p.h" + +#include <CLucene.h> +#include <CLucene/util/Reader.h> +#include <CLucene/document/Document.h> + +QT_BEGIN_NAMESPACE + +QCLuceneDocumentPrivate::QCLuceneDocumentPrivate() + : QSharedData() +{ + document = 0; + deleteCLuceneDocument = true; +} + +QCLuceneDocumentPrivate::QCLuceneDocumentPrivate(const QCLuceneDocumentPrivate &other) + : QSharedData() +{ + document = _CL_POINTER(other.document); +} + +QCLuceneDocumentPrivate::~QCLuceneDocumentPrivate() +{ + if (deleteCLuceneDocument) + _CLDECDELETE(document); +} + + +QCLuceneDocument::QCLuceneDocument() + : d(new QCLuceneDocumentPrivate()) +{ + // nothing todo + d->document = new lucene::document::Document(); +} + +QCLuceneDocument::~QCLuceneDocument() +{ + qDeleteAll(fieldList); + fieldList.clear(); +} + +void QCLuceneDocument::add(QCLuceneField *field) +{ + field->d->deleteCLuceneField = false; + d->document->add(*field->d->field); + fieldList.append(field); +} + +QCLuceneField* QCLuceneDocument::getField(const QString &name) const +{ + QCLuceneField* field = 0; + foreach (field, fieldList) { + if (field->name() == name && field->d->field != 0) + return field; + } + + field = 0; + TCHAR *fieldName = QStringToTChar(name); + lucene::document::Field *f = d->document->getField(fieldName); + if (f) { + field = new QCLuceneField(); + field->d->field = f; + fieldList.append(field); + field->d->deleteCLuceneField = false; + + lucene::util::Reader *r = f->readerValue(); + if (r) { + field->reader->d->reader = r; + field->reader->d->deleteCLuceneReader = false; + } + } + delete [] fieldName; + + return field; +} + +QString QCLuceneDocument::get(const QString &name) const +{ + QCLuceneField* field = getField(name); + if (field) + return field->stringValue(); + + return QString(); +} + +QString QCLuceneDocument::toString() const +{ + return TCharToQString(d->document->toString()); +} + +void QCLuceneDocument::setBoost(qreal boost) +{ + d->document->setBoost(qreal(boost)); +} + +qreal QCLuceneDocument::getBoost() const +{ + return qreal(d->document->getBoost()); +} + +void QCLuceneDocument::removeField(const QString &name) +{ + TCHAR *fieldName = QStringToTChar(name); + d->document->removeField(fieldName); + delete [] fieldName; + + QList<QCLuceneField*> tmp; + lucene::document::DocumentFieldEnumeration *dfe = d->document->fields(); + while (dfe->hasMoreElements()) { + const lucene::document::Field* f = dfe->nextElement(); + foreach (QCLuceneField* field, fieldList) { + if (f == field->d->field) { + tmp.append(field); + break; + } + } + } + _CLDELETE(dfe); + fieldList = tmp; +} + +void QCLuceneDocument::removeFields(const QString &name) +{ + for (qint32 i = fieldList.count() -1; i >= 0; --i) { + QCLuceneField* field = fieldList.at(i); + if (field->name() == name) + delete fieldList.takeAt(i); + } + + TCHAR *fieldName = QStringToTChar(name); + d->document->removeFields(fieldName); + delete [] fieldName; +} + +QStringList QCLuceneDocument::getValues(const QString &name) const +{ + TCHAR *fieldName = QStringToTChar(name); + TCHAR **values = d->document->getValues(fieldName); + + QStringList retValue; + if (values) { + for (qint32 i = 0; 0 != values[i]; ++i) { + retValue.append(TCharToQString((const TCHAR*)values[i])); + delete [] values[i]; values[i] = 0; + } + delete values; + } + + delete [] fieldName; + return retValue; +} + +void QCLuceneDocument::clear() +{ + d->document->clear(); + qDeleteAll(fieldList); + fieldList.clear(); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qdocument_p.h b/tools/assistant/lib/fulltextsearch/qdocument_p.h new file mode 100644 index 0000000..45f3d00 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qdocument_p.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QDOCUMENT_P_H +#define QDOCUMENT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qfield_p.h" +#include "qclucene_global_p.h" + +#include <QtCore/QList> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(document) + class Document; +CL_NS_END +CL_NS_USE(document) + +QT_BEGIN_NAMESPACE + +class QCLuceneHits; +class QCLuceneIndexReader; +class QCLuceneIndexWriter; +class QCLuceneIndexSearcher; +class QCLuceneMultiSearcher; + +class QHELP_EXPORT QCLuceneDocumentPrivate : public QSharedData +{ +public: + QCLuceneDocumentPrivate(); + QCLuceneDocumentPrivate(const QCLuceneDocumentPrivate &other); + + ~QCLuceneDocumentPrivate(); + + Document *document; + bool deleteCLuceneDocument; + +private: + QCLuceneDocumentPrivate &operator=(const QCLuceneDocumentPrivate &other); +}; + +class QHELP_EXPORT QCLuceneDocument +{ +public: + QCLuceneDocument(); + ~QCLuceneDocument(); + + void add(QCLuceneField *field); + QCLuceneField* getField(const QString &name) const; + QString get(const QString &name) const; + QString toString() const; + void setBoost(qreal boost); + qreal getBoost() const; + void removeField(const QString &name); + void removeFields(const QString &name); + QStringList getValues(const QString &name) const; + void clear(); + +protected: + friend class QCLuceneHits; + friend class QCLuceneIndexReader; + friend class QCLuceneIndexWriter; + friend class QCLuceneIndexSearcher; + friend class QCLuceneMultiSearcher; + QSharedDataPointer<QCLuceneDocumentPrivate> d; + +private: + mutable QList<QCLuceneField*> fieldList; +}; + +QT_END_NAMESPACE + +#endif // QDOCUMENT_P_H diff --git a/tools/assistant/lib/fulltextsearch/qfield.cpp b/tools/assistant/lib/fulltextsearch/qfield.cpp new file mode 100644 index 0000000..0c64fa8 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qfield.cpp @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qfield_p.h" +#include "qreader_p.h" +#include "qclucene_global_p.h" + +#include <CLucene.h> +#include <CLucene/document/Field.h> + +QT_BEGIN_NAMESPACE + +QCLuceneFieldPrivate::QCLuceneFieldPrivate() + : QSharedData() +{ + field = 0; + deleteCLuceneField = true; +} + +QCLuceneFieldPrivate::QCLuceneFieldPrivate(const QCLuceneFieldPrivate &other) + : QSharedData() +{ + field = _CL_POINTER(other.field); +} + +QCLuceneFieldPrivate::~QCLuceneFieldPrivate() +{ + if (deleteCLuceneField) + _CLDECDELETE(field); +} + + +QCLuceneField::QCLuceneField() + : d(new QCLuceneFieldPrivate()) + , reader(0) +{ + // nothing todo +} + +QCLuceneField::QCLuceneField(const QString &name, const QString &value, int configs) + : d(new QCLuceneFieldPrivate()) + , reader(0) +{ + TCHAR* fieldName = QStringToTChar(name); + TCHAR* fieldValue = QStringToTChar(value); + + d->field = new lucene::document::Field(fieldName, fieldValue, configs); + + delete [] fieldName; + delete [] fieldValue; +} + +QCLuceneField::QCLuceneField(const QString &name, QCLuceneReader *reader, + int configs) + : d(new QCLuceneFieldPrivate()) + , reader(reader) +{ + TCHAR* fieldName = QStringToTChar(name); + + reader->d->deleteCLuceneReader = false; // clucene takes ownership + d->field = new lucene::document::Field(fieldName, reader->d->reader, configs); + + delete [] fieldName; +} + +QCLuceneField::~QCLuceneField() +{ + delete reader; +} + +QString QCLuceneField::name() const +{ + return TCharToQString(d->field->name()); +} + +QString QCLuceneField::stringValue() const +{ + return TCharToQString((const TCHAR*)d->field->stringValue()); +} + +QCLuceneReader* QCLuceneField::readerValue() const +{ + return reader; +} + +bool QCLuceneField::isStored() const +{ + return d->field->isStored(); +} + +bool QCLuceneField::isIndexed() const +{ + return d->field->isIndexed(); +} + +bool QCLuceneField::isTokenized() const +{ + return d->field->isTokenized(); +} + +bool QCLuceneField::isCompressed() const +{ + return d->field->isCompressed(); +} + +void QCLuceneField::setConfig(int termVector) +{ + d->field->setConfig(termVector); +} + +bool QCLuceneField::isTermVectorStored() const +{ + return d->field->isTermVectorStored(); +} + +bool QCLuceneField::isStoreOffsetWithTermVector() const +{ + return d->field->isStoreOffsetWithTermVector(); +} + +bool QCLuceneField::isStorePositionWithTermVector() const +{ + return d->field->isStorePositionWithTermVector(); +} + +qreal QCLuceneField::getBoost() const +{ + return qreal(d->field->getBoost()); +} + +void QCLuceneField::setBoost(qreal value) +{ + d->field->setBoost(qreal(value)); +} + +bool QCLuceneField::isBinary() const +{ + return d->field->isBinary(); +} + +bool QCLuceneField::getOmitNorms() const +{ + return d->field->getOmitNorms(); +} + +void QCLuceneField::setOmitNorms(bool omitNorms) +{ + d->field->setOmitNorms(omitNorms); +} + +QString QCLuceneField::toString() const +{ + return TCharToQString(d->field->toString()); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qfield_p.h b/tools/assistant/lib/fulltextsearch/qfield_p.h new file mode 100644 index 0000000..86b6440 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qfield_p.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QFIELD_P_H +#define QFIELD_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qclucene_global_p.h" + +#include <QtCore/QString> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(document) + class Field; +CL_NS_END +CL_NS_USE(document) + +QT_BEGIN_NAMESPACE + +class QCLuceneReader; +class QCLuceneDocument; + +class QHELP_EXPORT QCLuceneFieldPrivate : public QSharedData +{ +public: + QCLuceneFieldPrivate(); + QCLuceneFieldPrivate(const QCLuceneFieldPrivate &other); + + ~QCLuceneFieldPrivate(); + + Field *field; + bool deleteCLuceneField; + +private: + QCLuceneFieldPrivate &operator=(const QCLuceneFieldPrivate &other); +}; + +class QHELP_EXPORT QCLuceneField +{ +public: + enum Store { + STORE_YES = 1, + STORE_NO = 2, + STORE_COMPRESS = 4 + }; + + enum Index { + INDEX_NO = 16, + INDEX_TOKENIZED = 32, + INDEX_UNTOKENIZED = 64, + INDEX_NONORMS = 128 + }; + + enum TermVector { + TERMVECTOR_NO = 256, + TERMVECTOR_YES = 512, + TERMVECTOR_WITH_POSITIONS = 1024, + TERMVECTOR_WITH_OFFSETS = 2048 + }; + + QCLuceneField(const QString &name, const QString &value, int configs); + QCLuceneField(const QString &name, QCLuceneReader *reader, int configs); + ~QCLuceneField(); + + QString name() const; + QString stringValue() const; + QCLuceneReader* readerValue() const; + bool isStored() const; + bool isIndexed() const; + bool isTokenized() const; + bool isCompressed() const; + void setConfig(int termVector); + bool isTermVectorStored() const; + bool isStoreOffsetWithTermVector() const; + bool isStorePositionWithTermVector() const; + qreal getBoost() const; + void setBoost(qreal value); + bool isBinary() const; + bool getOmitNorms() const; + void setOmitNorms(bool omitNorms); + QString toString() const; + +protected: + QCLuceneField(); + friend class QCLuceneDocument; + QSharedDataPointer<QCLuceneFieldPrivate> d; + +private: + QCLuceneReader* reader; +}; + +QT_END_NAMESPACE + +#endif // QFIELD_P_H diff --git a/tools/assistant/lib/fulltextsearch/qfilter.cpp b/tools/assistant/lib/fulltextsearch/qfilter.cpp new file mode 100644 index 0000000..2437339 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qfilter.cpp @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qfilter_p.h" + +#include <CLucene.h> +#include <CLucene/search/Filter.h> + +QT_BEGIN_NAMESPACE + +QCLuceneFilterPrivate::QCLuceneFilterPrivate() + : QSharedData() +{ + filter = 0; + deleteCLuceneFilter = true; +} + +QCLuceneFilterPrivate::QCLuceneFilterPrivate(const QCLuceneFilterPrivate &other) + : QSharedData() +{ + filter = _CL_POINTER(other.filter); +} + +QCLuceneFilterPrivate::~QCLuceneFilterPrivate () +{ + if (deleteCLuceneFilter) + _CLDECDELETE(filter); +} + + +QCLuceneFilter::QCLuceneFilter() + : d(new QCLuceneFilterPrivate()) +{ + // nothing todo +} + +QCLuceneFilter::~QCLuceneFilter() +{ + // nothing todo +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qfilter_p.h b/tools/assistant/lib/fulltextsearch/qfilter_p.h new file mode 100644 index 0000000..fcc0674 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qfilter_p.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QFilter_P_H +#define QFilter_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qclucene_global_p.h" + +#include <QtCore/QSharedData> +#include <QtCore/QSharedDataPointer> + +CL_NS_DEF(search) + class Filter; +CL_NS_END +CL_NS_USE(search) + +QT_BEGIN_NAMESPACE + +class QCLuceneHits; +class QCLuceneSearcher; + +class QHELP_EXPORT QCLuceneFilterPrivate : public QSharedData +{ +public: + QCLuceneFilterPrivate(); + QCLuceneFilterPrivate(const QCLuceneFilterPrivate &other); + + ~QCLuceneFilterPrivate (); + + Filter *filter; + bool deleteCLuceneFilter; + +private: + QCLuceneFilterPrivate &operator=(const QCLuceneFilterPrivate &other); +}; + +class QHELP_EXPORT QCLuceneFilter +{ + QCLuceneFilter(); + virtual ~QCLuceneFilter(); + +protected: + friend class QCLuceneHits; + friend class QCLuceneSearcher; + QSharedDataPointer<QCLuceneFilterPrivate> d; +}; + +QT_END_NAMESPACE + +#endif // QFilter_P_H diff --git a/tools/assistant/lib/fulltextsearch/qhits.cpp b/tools/assistant/lib/fulltextsearch/qhits.cpp new file mode 100644 index 0000000..b3dbea7 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qhits.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qhits_p.h" +#include "qsearchable_p.h" + +#include <CLucene.h> +#include <CLucene/search/SearchHeader.h> + +QT_BEGIN_NAMESPACE + +QCLuceneHitsPrivate::QCLuceneHitsPrivate() + : QSharedData() +{ + hits = 0; + deleteCLuceneHits = true; +} + +QCLuceneHitsPrivate::QCLuceneHitsPrivate(const QCLuceneHitsPrivate &other) + : QSharedData() +{ + hits = _CL_POINTER(other.hits); +} + +QCLuceneHitsPrivate::~QCLuceneHitsPrivate() +{ + if (deleteCLuceneHits) + _CLDECDELETE(hits); +} + + +QCLuceneHits::QCLuceneHits(const QCLuceneSearcher &searcher, + const QCLuceneQuery &query, const QCLuceneFilter &filter) + : d(new QCLuceneHitsPrivate()) +{ + d->hits = new lucene::search::Hits(searcher.d->searchable, query.d->query, + filter.d->filter); +} + +QCLuceneHits::QCLuceneHits(const QCLuceneSearcher &searcher, const QCLuceneQuery &query, + const QCLuceneFilter &filter, const QCLuceneSort &sort) + : d(new QCLuceneHitsPrivate()) +{ + d->hits = new lucene::search::Hits(searcher.d->searchable, query.d->query, + filter.d->filter, sort.d->sort); +} + +QCLuceneHits::~QCLuceneHits() +{ + // nothing todo +} + +QCLuceneDocument QCLuceneHits::document(const qint32 index) +{ + // TODO: check this + QCLuceneDocument document; + document.d->deleteCLuceneDocument = false; + lucene::document::Document &doc = d->hits->doc(int32_t(index)); + document.d->document = &doc; + + return document; +} + +qint32 QCLuceneHits::length() const +{ + return qint32(d->hits->length()); +} + +qint32 QCLuceneHits::id(const qint32 index) +{ + return qint32(d->hits->id(int32_t(index))); +} + +qreal QCLuceneHits::score(const qint32 index) +{ + return qreal(d->hits->score(int32_t(index))); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qhits_p.h b/tools/assistant/lib/fulltextsearch/qhits_p.h new file mode 100644 index 0000000..fb6666b --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qhits_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QHITS_P_H +#define QHITS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qsort_p.h" +#include "qquery_p.h" +#include "qfilter_p.h" +#include "qdocument_p.h" +#include "qclucene_global_p.h" + +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(search) + class Hits; +CL_NS_END +CL_NS_USE(search) + +QT_BEGIN_NAMESPACE + +class QCLuceneSearcher; + +class QHELP_EXPORT QCLuceneHitsPrivate : public QSharedData +{ +public: + QCLuceneHitsPrivate(); + QCLuceneHitsPrivate(const QCLuceneHitsPrivate &other); + + ~QCLuceneHitsPrivate(); + + Hits *hits; + bool deleteCLuceneHits; + +private: + QCLuceneHitsPrivate &operator=(const QCLuceneHitsPrivate &other); +}; + +class QHELP_EXPORT QCLuceneHits +{ +public: + QCLuceneHits(const QCLuceneSearcher &searcher, const QCLuceneQuery &query, + const QCLuceneFilter &filter); + QCLuceneHits(const QCLuceneSearcher &searcher, const QCLuceneQuery &query, + const QCLuceneFilter &filter, const QCLuceneSort &sort); + virtual ~QCLuceneHits(); + + QCLuceneDocument document(const qint32 index); + qint32 length() const; + qint32 id (const qint32 index); + qreal score(const qint32 index); + +protected: + friend class QCLuceneSearcher; + QSharedDataPointer<QCLuceneHitsPrivate> d; +}; + +QT_END_NAMESPACE + +#endif // QHITS_P_H diff --git a/tools/assistant/lib/fulltextsearch/qindexreader.cpp b/tools/assistant/lib/fulltextsearch/qindexreader.cpp new file mode 100644 index 0000000..5f967cc --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qindexreader.cpp @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qindexreader_p.h" +#include "qclucene_global_p.h" + +#include <CLucene.h> +#include <CLucene/index/IndexReader.h> + +QT_BEGIN_NAMESPACE + +QCLuceneIndexReaderPrivate::QCLuceneIndexReaderPrivate() + : QSharedData() +{ + reader = 0; + deleteCLuceneIndexReader = true; +} + +QCLuceneIndexReaderPrivate::QCLuceneIndexReaderPrivate(const QCLuceneIndexReaderPrivate &other) + : QSharedData() +{ + reader = _CL_POINTER(other.reader); +} + +QCLuceneIndexReaderPrivate::~QCLuceneIndexReaderPrivate() +{ + if (deleteCLuceneIndexReader) + _CLDECDELETE(reader); +} + + +QCLuceneIndexReader::QCLuceneIndexReader() + : d(new QCLuceneIndexReaderPrivate()) +{ + // nothing todo, private +} + +QCLuceneIndexReader::~QCLuceneIndexReader() +{ + // nothing todo +} + +bool QCLuceneIndexReader::isLuceneFile(const QString &filename) +{ + using namespace lucene::index; + + return IndexReader::isLuceneFile(filename); +} + +bool QCLuceneIndexReader::indexExists(const QString &directory) +{ + using namespace lucene::index; + return IndexReader::indexExists(directory); +} + +QCLuceneIndexReader QCLuceneIndexReader::open(const QString &path) +{ + using namespace lucene::index; + + QCLuceneIndexReader indexReader; + indexReader.d->reader = IndexReader::open(path); + + return indexReader; +} + +void QCLuceneIndexReader::unlock(const QString &path) +{ + using namespace lucene::index; + IndexReader::unlock(path); +} + +bool QCLuceneIndexReader::isLocked(const QString &directory) +{ + using namespace lucene::index; + return IndexReader::isLocked(directory); +} + +quint64 QCLuceneIndexReader::lastModified(const QString &directory) +{ + using namespace lucene::index; + return quint64(IndexReader::lastModified(directory)); +} + +qint64 QCLuceneIndexReader::getCurrentVersion(const QString &directory) +{ + using namespace lucene::index; + return qint64(IndexReader::getCurrentVersion(directory)); +} + +void QCLuceneIndexReader::close() +{ + d->reader->close(); +} + +bool QCLuceneIndexReader::isCurrent() +{ + return d->reader->isCurrent(); +} + +void QCLuceneIndexReader::undeleteAll() +{ + d->reader->undeleteAll(); +} + +qint64 QCLuceneIndexReader::getVersion() +{ + return qint64(d->reader->getVersion()); +} + +void QCLuceneIndexReader::deleteDocument(qint32 docNum) +{ + d->reader->deleteDocument(int32_t(docNum)); +} + +bool QCLuceneIndexReader::hasNorms(const QString &field) +{ + TCHAR *fieldName = QStringToTChar(field); + bool retValue = d->reader->hasNorms(fieldName); + delete [] fieldName; + + return retValue; +} + +qint32 QCLuceneIndexReader::deleteDocuments(const QCLuceneTerm &term) +{ + return d->reader->deleteDocuments(term.d->term); +} + +bool QCLuceneIndexReader::document(qint32 index, QCLuceneDocument &document) +{ + if (!document.d->document) + document.d->document = new lucene::document::Document(); + + if (d->reader->document(int32_t(index), document.d->document)) + return true; + + return false; +} + +void QCLuceneIndexReader::setNorm(qint32 doc, const QString &field, qreal value) +{ + TCHAR *fieldName = QStringToTChar(field); + d->reader->setNorm(int32_t(doc), fieldName, qreal(value)); + delete [] fieldName; +} + +void QCLuceneIndexReader::setNorm(qint32 doc, const QString &field, quint8 value) +{ + TCHAR *fieldName = QStringToTChar(field); + d->reader->setNorm(int32_t(doc), fieldName, uint8_t(value)); + delete [] fieldName; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qindexreader_p.h b/tools/assistant/lib/fulltextsearch/qindexreader_p.h new file mode 100644 index 0000000..4a7330d --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qindexreader_p.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QINDEXREADER_P_H +#define QINDEXREADER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qterm_p.h" +#include "qdocument_p.h" +#include "qclucene_global_p.h" + +#include <QtCore/QList> +#include <QtCore/QString> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(index) + class IndexReader; +CL_NS_END +CL_NS_USE(index) + +QT_BEGIN_NAMESPACE + +class QCLuceneIndexWriter; +class QCLuceneIndexSearcher; + +class QHELP_EXPORT QCLuceneIndexReaderPrivate : public QSharedData +{ +public: + QCLuceneIndexReaderPrivate(); + QCLuceneIndexReaderPrivate(const QCLuceneIndexReaderPrivate &other); + + ~QCLuceneIndexReaderPrivate(); + + IndexReader *reader; + bool deleteCLuceneIndexReader; + +private: + QCLuceneIndexReaderPrivate &operator=(const QCLuceneIndexReaderPrivate &other); +}; + +class QHELP_EXPORT QCLuceneIndexReader +{ +public: + enum FieldOption { + ALL = 1, + INDEXED = 2, + UNINDEXED = 4, + INDEXED_WITH_TERMVECTOR = 8, + INDEXED_NO_TERMVECTOR = 16, + TERMVECTOR = 32, + TERMVECTOR_WITH_POSITION = 64, + TERMVECTOR_WITH_OFFSET = 128, + TERMVECTOR_WITH_POSITION_OFFSET = 256 + }; + + virtual ~QCLuceneIndexReader(); + + static bool isLuceneFile(const QString &filename); + static bool indexExists(const QString &directory); + static QCLuceneIndexReader open(const QString &path); + + static void unlock(const QString &path); + static bool isLocked(const QString &directory); + + static quint64 lastModified(const QString &directory); + static qint64 getCurrentVersion(const QString &directory); + + void close(); + bool isCurrent(); + void undeleteAll(); + qint64 getVersion(); + void deleteDocument(qint32 docNum); + bool hasNorms(const QString &field); + qint32 deleteDocuments(const QCLuceneTerm &term); + bool document(qint32 index, QCLuceneDocument &document); + void setNorm(qint32 doc, const QString &field, qreal value); + void setNorm(qint32 doc, const QString &field, quint8 value); + +protected: + friend class QCLuceneIndexWriter; + friend class QCLuceneIndexSearcher; + QSharedDataPointer<QCLuceneIndexReaderPrivate> d; + +private: + QCLuceneIndexReader(); +}; + +QT_END_NAMESPACE + +#endif // QINDEXREADER_P_H diff --git a/tools/assistant/lib/fulltextsearch/qindexwriter.cpp b/tools/assistant/lib/fulltextsearch/qindexwriter.cpp new file mode 100644 index 0000000..890cc67 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qindexwriter.cpp @@ -0,0 +1,183 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qindexwriter_p.h" +#include "qindexreader_p.h" + +#include <CLucene.h> +#include <CLucene/index/IndexWriter.h> + +QT_BEGIN_NAMESPACE + +QCLuceneIndexWriterPrivate::QCLuceneIndexWriterPrivate() + : QSharedData() +{ + writer = 0; + deleteCLuceneIndexWriter = true; +} + +QCLuceneIndexWriterPrivate::QCLuceneIndexWriterPrivate(const QCLuceneIndexWriterPrivate &other) + : QSharedData() +{ + writer = _CL_POINTER(other.writer); +} + +QCLuceneIndexWriterPrivate::~QCLuceneIndexWriterPrivate() +{ + if (deleteCLuceneIndexWriter) + _CLDECDELETE(writer); +} + + +QCLuceneIndexWriter::QCLuceneIndexWriter(const QString &path, + QCLuceneAnalyzer &analyzer, + bool create, bool closeDir) + : d(new QCLuceneIndexWriterPrivate()) + , analyzer(analyzer) +{ + d->writer = new lucene::index::IndexWriter(path, + analyzer.d->analyzer, create, closeDir); +} + +QCLuceneIndexWriter::~QCLuceneIndexWriter() +{ + // nothing todo +} + +void QCLuceneIndexWriter::close() +{ + d->writer->close(); +} + +void QCLuceneIndexWriter::optimize() +{ + d->writer->optimize(); +} + +qint32 QCLuceneIndexWriter::docCount() +{ + return qint32(d->writer->docCount()); +} + +QCLuceneAnalyzer QCLuceneIndexWriter::getAnalyzer() +{ + return analyzer; +} + +void QCLuceneIndexWriter::addIndexes(const QList<QCLuceneIndexReader*> &readers) +{ + using namespace lucene::index; + IndexReader** readerArray = new IndexReader*[readers.count()]; + + for (int i = 0; i < readers.count(); ++i) + readerArray[i] = (readers.at(i))->d->reader; + + d->writer->addIndexes(readerArray); + delete readerArray; +} + +void QCLuceneIndexWriter::addDocument(QCLuceneDocument &doc, + QCLuceneAnalyzer &analyzer) +{ + if (doc.d->document) + d->writer->addDocument(doc.d->document, analyzer.d->analyzer); +} + +qint32 QCLuceneIndexWriter::getMaxFieldLength() const +{ + return qint32(d->writer->getMaxFieldLength()); +} + +void QCLuceneIndexWriter::setMaxFieldLength(qint32 value) +{ + d->writer->setMaxFieldLength(int32_t(value)); +} + +qint32 QCLuceneIndexWriter::getMaxBufferedDocs() const +{ + return qint32(d->writer->getMaxBufferedDocs()); +} + +void QCLuceneIndexWriter::setMaxBufferedDocs(qint32 value) +{ + d->writer->setMaxBufferedDocs(int32_t(value)); +} + +qint64 QCLuceneIndexWriter::getWriteLockTimeout() const +{ + return qint64(d->writer->getWriteLockTimeout()); +} + +void QCLuceneIndexWriter::setWriteLockTimeout(qint64 writeLockTimeout) +{ + d->writer->setWriteLockTimeout(int64_t(writeLockTimeout)); +} + +qint64 QCLuceneIndexWriter::getCommitLockTimeout() const +{ + return qint64(d->writer->getCommitLockTimeout()); +} + +void QCLuceneIndexWriter::setCommitLockTimeout(qint64 commitLockTimeout) +{ + d->writer->setCommitLockTimeout(int64_t(commitLockTimeout)); +} + +qint32 QCLuceneIndexWriter::getMergeFactor() const +{ + return qint32(d->writer->getMergeFactor()); +} + +void QCLuceneIndexWriter::setMergeFactor(qint32 value) +{ + d->writer->setMergeFactor(int32_t(value)); +} + +qint32 QCLuceneIndexWriter::getTermIndexInterval() const +{ + return qint32(d->writer->getTermIndexInterval()); +} + +void QCLuceneIndexWriter::setTermIndexInterval(qint32 interval) +{ + d->writer->setTermIndexInterval(int32_t(interval)); +} + +qint32 QCLuceneIndexWriter::getMinMergeDocs() const +{ + return qint32(d->writer->getMinMergeDocs()); +} + +void QCLuceneIndexWriter::setMinMergeDocs(qint32 value) +{ + d->writer->setMinMergeDocs(int32_t(value)); +} + +qint32 QCLuceneIndexWriter::getMaxMergeDocs() const +{ + return qint32(d->writer->getMaxMergeDocs()); +} + +void QCLuceneIndexWriter::setMaxMergeDocs(qint32 value) +{ + d->writer->setMaxMergeDocs(int32_t(value)); +} + +bool QCLuceneIndexWriter::getUseCompoundFile() const +{ + return d->writer->getUseCompoundFile(); +} + +void QCLuceneIndexWriter::setUseCompoundFile(bool value) +{ + d->writer->setUseCompoundFile(value); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qindexwriter_p.h b/tools/assistant/lib/fulltextsearch/qindexwriter_p.h new file mode 100644 index 0000000..e793494 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qindexwriter_p.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QINDEXWRITER_P_H +#define QINDEXWRITER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qanalyzer_p.h" +#include "qdocument_p.h" +#include "qclucene_global_p.h" + +#include <QtCore/QString> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(index) + class IndexWriter; +CL_NS_END +CL_NS_USE(index) + +QT_BEGIN_NAMESPACE + +class QCLuceneIndexReader; + +class QHELP_EXPORT QCLuceneIndexWriterPrivate : public QSharedData +{ +public: + QCLuceneIndexWriterPrivate(); + QCLuceneIndexWriterPrivate(const QCLuceneIndexWriterPrivate &other); + + ~QCLuceneIndexWriterPrivate(); + + IndexWriter *writer; + bool deleteCLuceneIndexWriter; + +private: + QCLuceneIndexWriterPrivate &operator=(const QCLuceneIndexWriterPrivate &other); +}; + +class QHELP_EXPORT QCLuceneIndexWriter +{ +public: + enum { + DEFAULT_MERGE_FACTOR = 10, + COMMIT_LOCK_TIMEOUT = 10000, + DEFAULT_MAX_BUFFERED_DOCS = 10, + DEFAULT_MAX_FIELD_LENGTH = 10000, + DEFAULT_TERM_INDEX_INTERVAL = 128, + DEFAULT_MAX_MERGE_DOCS = 0x7FFFFFFFL + }; + + QCLuceneIndexWriter(const QString &path, QCLuceneAnalyzer &analyzer, + bool create, bool closeDir = true); + virtual ~QCLuceneIndexWriter(); + + void close(); + void optimize(); + qint32 docCount(); + QCLuceneAnalyzer getAnalyzer(); + + void addIndexes(const QList<QCLuceneIndexReader*> &readers); + void addDocument(QCLuceneDocument &doc, QCLuceneAnalyzer &analyzer); + + qint32 getMaxFieldLength() const; + void setMaxFieldLength(qint32 value); + + qint32 getMaxBufferedDocs() const; + void setMaxBufferedDocs(qint32 value); + + qint64 getWriteLockTimeout() const; + void setWriteLockTimeout(qint64 writeLockTimeout); + + qint64 getCommitLockTimeout() const; + void setCommitLockTimeout(qint64 commitLockTimeout); + + qint32 getMergeFactor() const; + void setMergeFactor(qint32 value); + + qint32 getTermIndexInterval() const; + void setTermIndexInterval(qint32 interval); + + qint32 getMinMergeDocs() const; + void setMinMergeDocs(qint32 value); + + qint32 getMaxMergeDocs() const; + void setMaxMergeDocs(qint32 value); + + bool getUseCompoundFile() const; + void setUseCompoundFile(bool value); + +protected: + QSharedDataPointer<QCLuceneIndexWriterPrivate> d; + +private: + QCLuceneAnalyzer analyzer; +}; + +QT_END_NAMESPACE + +#endif // QINDEXWRITER_P_H diff --git a/tools/assistant/lib/fulltextsearch/qquery.cpp b/tools/assistant/lib/fulltextsearch/qquery.cpp new file mode 100644 index 0000000..2210220 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qquery.cpp @@ -0,0 +1,350 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qquery_p.h" +#include "qclucene_global_p.h" + +#include <CLucene.h> +#include <CLucene/search/PhraseQuery.h> +#include <CLucene/search/SearchHeader.h> + +QT_BEGIN_NAMESPACE + +QCLuceneQueryPrivate::QCLuceneQueryPrivate() + : QSharedData() +{ + query = 0; + deleteCLuceneQuery = true; +} + +QCLuceneQueryPrivate::QCLuceneQueryPrivate(const QCLuceneQueryPrivate &other) + : QSharedData() +{ + query = _CL_POINTER(other.query); +} + +QCLuceneQueryPrivate::~QCLuceneQueryPrivate() +{ + if (deleteCLuceneQuery) + _CLDECDELETE(query); +} + + +QCLuceneQuery::QCLuceneQuery() + : d(new QCLuceneQueryPrivate()) +{ + // nothing todo, private +} + +QCLuceneQuery::~QCLuceneQuery() +{ + // nothing todo +} + +void QCLuceneQuery::setBoost(qreal boost) +{ + d->query->setBoost(qreal(boost)); +} + +qreal QCLuceneQuery::getBoost() const +{ + return qreal(d->query->getBoost()); +} + +QString QCLuceneQuery::getQueryName() const +{ + return TCharToQString(d->query->getQueryName()); +} + +bool QCLuceneQuery::instanceOf(const QString &other) const +{ + if (other == getQueryName()) + return true; + + return false; +} + +QString QCLuceneQuery::toString(const QString &field) const +{ + TCHAR *fieldName = QStringToTChar(field); + QString retValue = TCharToQString(d->query->toString(fieldName)); + delete [] fieldName; + + return retValue; +} + +quint32 QCLuceneQuery::hashCode() const +{ + return quint32(d->query->hashCode()); +} + +QString QCLuceneQuery::toString() const +{ + return TCharToQString(d->query->toString()); +} + +bool QCLuceneQuery::equals(const QCLuceneQuery &other) const +{ + return d->query->equals(other.d->query); +} + + +QCLucenePrefixQuery::QCLucenePrefixQuery(const QCLuceneTerm &prefix) + : QCLuceneQuery() + , prefix(prefix) +{ + d->query = new lucene::search::PrefixQuery(prefix.d->term); +} + +QCLucenePrefixQuery::~QCLucenePrefixQuery() +{ + // nothing todo +} + +QString QCLucenePrefixQuery::getClassName() +{ + return TCharToQString(lucene::search::PrefixQuery::getClassName()); +} + +QCLuceneTerm QCLucenePrefixQuery::getPrefix() const +{ + return prefix; +} + + +QCLuceneRangeQuery::QCLuceneRangeQuery(const QCLuceneTerm &lowerTerm, + const QCLuceneTerm &upperTerm, + bool inclusive) + : QCLuceneQuery() + , lowerTerm(lowerTerm) + , upperTerm(upperTerm) +{ + d->query = new lucene::search::RangeQuery(lowerTerm.d->term, + upperTerm.d->term, inclusive); +} + +QCLuceneRangeQuery::~QCLuceneRangeQuery() +{ + // nothing todo +} + +QString QCLuceneRangeQuery::getClassName() +{ + return TCharToQString(lucene::search::RangeQuery::getClassName()); +} + +QCLuceneTerm QCLuceneRangeQuery::getLowerTerm() const +{ + return lowerTerm; +} + +QCLuceneTerm QCLuceneRangeQuery::getUpperTerm() const +{ + return upperTerm; +} + +bool QCLuceneRangeQuery::isInclusive() const +{ + lucene::search::RangeQuery *query = + static_cast<lucene::search::RangeQuery*> (d->query); + + if (query == 0) + return false; + + return query->isInclusive(); +} + +QString QCLuceneRangeQuery::getField() const +{ + lucene::search::RangeQuery *query = + static_cast<lucene::search::RangeQuery*> (d->query); + + if (query == 0) + return QString(); + + return TCharToQString(query->getField()); +} + + +QCLuceneTermQuery::QCLuceneTermQuery(const QCLuceneTerm &term) + : QCLuceneQuery() + , term(term) +{ + d->query = new lucene::search::TermQuery(term.d->term); +} + +QCLuceneTermQuery::~QCLuceneTermQuery() +{ + // nothing todo +} + +QString QCLuceneTermQuery::getClassName() +{ + return TCharToQString(lucene::search::TermQuery::getClassName()); +} + +QCLuceneTerm QCLuceneTermQuery::getTerm() const +{ + return term; +} + + +QCLuceneBooleanQuery::QCLuceneBooleanQuery() + : QCLuceneQuery() +{ + d->query = new lucene::search::BooleanQuery(); +} + +QCLuceneBooleanQuery::~QCLuceneBooleanQuery() +{ + qDeleteAll(queries); +} + +QString QCLuceneBooleanQuery::getClassName() +{ + return TCharToQString(lucene::search::BooleanQuery::getClassName()); +} + +quint32 QCLuceneBooleanQuery::getClauseCount() const +{ + lucene::search::BooleanQuery *query = + static_cast<lucene::search::BooleanQuery*> (d->query); + + if (query == 0) + return 1024; + + return quint32(query->getClauseCount()); +} + +quint32 QCLuceneBooleanQuery::getMaxClauseCount() const +{ + lucene::search::BooleanQuery *query = + static_cast<lucene::search::BooleanQuery*> (d->query); + + if (query == 0) + return 1024; + + return quint32(query->getMaxClauseCount()); +} + +void QCLuceneBooleanQuery::setMaxClauseCount(quint32 maxClauseCount) +{ + lucene::search::BooleanQuery *query = + static_cast<lucene::search::BooleanQuery*> (d->query); + + if (query == 0) + return; + + query->setMaxClauseCount(size_t(maxClauseCount)); +} + +void QCLuceneBooleanQuery::add(QCLuceneQuery *query, bool required, bool prohibited) +{ + add(query, false, required, prohibited); +} + +void QCLuceneBooleanQuery::add(QCLuceneQuery *query, bool delQuery, + bool required, bool prohibited) +{ + lucene::search::BooleanQuery *booleanQuery = + static_cast<lucene::search::BooleanQuery*> (d->query); + + if (booleanQuery == 0) + return; + + booleanQuery->add(query->d->query, delQuery, required, prohibited); + + if (delQuery) { + queries.append(query); + query->d->deleteCLuceneQuery = false; + } +} + + +QCLucenePhraseQuery::QCLucenePhraseQuery() + : QCLuceneQuery() +{ + d->query = new lucene::search::PhraseQuery(); +} + +QCLucenePhraseQuery::~QCLucenePhraseQuery() +{ + termList.clear(); +} + +QString QCLucenePhraseQuery::getClassName() +{ + return TCharToQString(lucene::search::RangeQuery::getClassName()); +} + +qint32 QCLucenePhraseQuery::getSlop() const +{ + lucene::search::PhraseQuery *phraseQuery = + static_cast<lucene::search::PhraseQuery*> (d->query); + + if (phraseQuery == 0) + return 0; + + return qint32(phraseQuery->getSlop()); +} + +void QCLucenePhraseQuery::setSlop(const qint32 slop) +{ + lucene::search::PhraseQuery *phraseQuery = + static_cast<lucene::search::PhraseQuery*> (d->query); + + if (phraseQuery == 0) + return; + + phraseQuery->setSlop(int32_t(slop)); +} + +void QCLucenePhraseQuery::addTerm(const QCLuceneTerm &term) +{ + lucene::search::PhraseQuery *phraseQuery = + static_cast<lucene::search::PhraseQuery*> (d->query); + + if (phraseQuery == 0) + return; + + termList.append(term); + phraseQuery->add(term.d->term); +} + +void QCLucenePhraseQuery::addTerm(const QCLuceneTerm &term, qint32 position) +{ + lucene::search::PhraseQuery *phraseQuery = + static_cast<lucene::search::PhraseQuery*> (d->query); + + if (phraseQuery == 0) + return; + + termList.insert(position, term); + phraseQuery->add(term.d->term, int32_t(position)); + +} + +QString QCLucenePhraseQuery::getFieldName() const +{ + lucene::search::PhraseQuery *phraseQuery = + static_cast<lucene::search::PhraseQuery*> (d->query); + + if (phraseQuery == 0) + return QString(); + + return TCharToQString(phraseQuery->getFieldName()); +} + +QList<QCLuceneTerm> QCLucenePhraseQuery::getTerms() const +{ + return termList; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qquery_p.h b/tools/assistant/lib/fulltextsearch/qquery_p.h new file mode 100644 index 0000000..42eaf07 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qquery_p.h @@ -0,0 +1,181 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QQUERY_P_H +#define QQUERY_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qterm_p.h" +#include "qclucene_global_p.h" + +#include <QtCore/QList> +#include <QtCore/QString> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(search) + class Query; +CL_NS_END +CL_NS_USE(search) + +QT_BEGIN_NAMESPACE + +class QCLuceneHits; +class QCLuceneTermQuery; +class QCLuceneRangeQuery; +class QCLuceneQueryParser; +class QCLucenePrefixQuery; +class QCLuceneBooleanQuery; +class QCLucenePhraseQuery; + +class QHELP_EXPORT QCLuceneQueryPrivate : public QSharedData +{ +public: + QCLuceneQueryPrivate(); + QCLuceneQueryPrivate(const QCLuceneQueryPrivate &other); + + ~QCLuceneQueryPrivate(); + + Query *query; + bool deleteCLuceneQuery; + +private: + QCLuceneQueryPrivate &operator=(const QCLuceneQueryPrivate &other); +}; + +class QHELP_EXPORT QCLuceneQuery +{ +public: + virtual ~QCLuceneQuery(); + + void setBoost(qreal boost); + qreal getBoost() const; + QString getQueryName() const; + bool instanceOf(const QString &other) const; + QString toString(const QString &field) const; + quint32 hashCode() const; + QString toString() const; + bool equals(const QCLuceneQuery &other) const; + +protected: + friend class QCLuceneHits; + friend class QCLuceneTermQuery; + friend class QCLuceneRangeQuery; + friend class QCLucenePrefixQuery; + friend class QCLuceneQueryParser; + friend class QCLuceneBooleanQuery; + friend class QCLucenePhraseQuery; + QSharedDataPointer<QCLuceneQueryPrivate> d; + +private: + QCLuceneQuery(); +}; + +class QHELP_EXPORT QCLucenePrefixQuery : public QCLuceneQuery +{ +public: + QCLucenePrefixQuery(const QCLuceneTerm &prefix); + ~QCLucenePrefixQuery(); + + static QString getClassName(); + + QCLuceneTerm getPrefix() const; + +private: + QCLuceneTerm prefix; +}; + +class QHELP_EXPORT QCLuceneRangeQuery : public QCLuceneQuery +{ +public: + QCLuceneRangeQuery(const QCLuceneTerm &lowerTerm, + const QCLuceneTerm &upperTerm, bool inclusive); + ~QCLuceneRangeQuery(); + + static QString getClassName(); + + QCLuceneTerm getLowerTerm() const; + QCLuceneTerm getUpperTerm() const; + + bool isInclusive() const; + QString getField() const; + +private: + QCLuceneTerm lowerTerm; + QCLuceneTerm upperTerm; +}; + +class QHELP_EXPORT QCLuceneTermQuery : public QCLuceneQuery +{ +public: + QCLuceneTermQuery(const QCLuceneTerm &term); + ~QCLuceneTermQuery(); + + static QString getClassName(); + + QCLuceneTerm getTerm() const; + +private: + QCLuceneTerm term; +}; + +class QHELP_EXPORT QCLuceneBooleanQuery : public QCLuceneQuery +{ +public: + QCLuceneBooleanQuery(); + ~QCLuceneBooleanQuery(); + + static QString getClassName(); + + quint32 getClauseCount() const; + quint32 getMaxClauseCount() const; + void setMaxClauseCount(quint32 maxClauseCount); + + void add(QCLuceneQuery *query, bool required, bool prohibited); + void add(QCLuceneQuery *query, bool delQuery, bool required, bool prohibited); + +private: + QList<QCLuceneQuery*> queries; +}; + +class QHELP_EXPORT QCLucenePhraseQuery : public QCLuceneQuery +{ +public: + QCLucenePhraseQuery(); + ~QCLucenePhraseQuery(); + + static QString getClassName(); + + qint32 getSlop() const; + void setSlop(const qint32 slop); + + void addTerm(const QCLuceneTerm &term); + void addTerm(const QCLuceneTerm &term, qint32 position); + + QString getFieldName() const; + QList<QCLuceneTerm> getTerms() const; + +private: + QList<QCLuceneTerm> termList; +}; + +QT_END_NAMESPACE + +#endif // QQUERY_P_H diff --git a/tools/assistant/lib/fulltextsearch/qqueryparser.cpp b/tools/assistant/lib/fulltextsearch/qqueryparser.cpp new file mode 100644 index 0000000..ce1b512 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qqueryparser.cpp @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qqueryparser_p.h" +#include "qquery_p.h" +#include "qclucene_global_p.h" + +#include <CLucene.h> +#include <CLucene/queryParser/QueryParser.h> + +QT_BEGIN_NAMESPACE + +QCLuceneQueryParserPrivate::QCLuceneQueryParserPrivate() + : QSharedData() +{ + queryParser = 0; + deleteCLuceneQueryParser = true; +} + +QCLuceneQueryParserPrivate::QCLuceneQueryParserPrivate(const QCLuceneQueryParserPrivate &other) + : QSharedData() +{ + queryParser = _CL_POINTER(other.queryParser); +} + +QCLuceneQueryParserPrivate::~QCLuceneQueryParserPrivate() +{ + if (deleteCLuceneQueryParser) + _CLDECDELETE(queryParser); +} + + +QCLuceneQueryParser::QCLuceneQueryParser(const QString &field, + QCLuceneAnalyzer &analyzer) + : d(new QCLuceneQueryParserPrivate()) + , field(field) + , analyzer(analyzer) +{ + TCHAR *fieldName = QStringToTChar(field); + + d->queryParser = new lucene::queryParser::QueryParser(fieldName, + analyzer.d->analyzer); + + delete [] fieldName; +} + +QCLuceneQueryParser::~QCLuceneQueryParser() +{ + // nothing todo +} + +QCLuceneQuery* QCLuceneQueryParser::parse(const QString &query) +{ + TCHAR *string = QStringToTChar(query); + + QCLuceneQuery *retValue = 0; + lucene::search::Query* q = d->queryParser->parse(string); + if (q) { + retValue = new QCLuceneQuery(); + retValue->d->query = q; + } + + delete [] string; + return retValue; +} + +QCLuceneQuery* QCLuceneQueryParser::parse(QCLuceneReader &reader) +{ + QCLuceneQuery *retValue = 0; + lucene::search::Query* q = d->queryParser->parse(reader.d->reader); + if (q) { + retValue = new QCLuceneQuery(); + retValue->d->query = q; + } + + return retValue; +} + +QCLuceneQuery* QCLuceneQueryParser::parse(const QString &query, const QString &field, + QCLuceneAnalyzer &analyzer) +{ + QCLuceneQueryParser parser(field, analyzer); + return parser.parse(query); +} + +QCLuceneAnalyzer QCLuceneQueryParser::getAnalyzer() +{ + return analyzer; +} + +QString QCLuceneQueryParser::getField() +{ + return field; +} + + +QCLuceneMultiFieldQueryParser::QCLuceneMultiFieldQueryParser( + const QStringList &fieldList, QCLuceneAnalyzer &analyzer) + : QCLuceneQueryParser(QLatin1String(""), analyzer) +{ + Q_UNUSED(fieldList) +} + +QCLuceneMultiFieldQueryParser::~QCLuceneMultiFieldQueryParser() +{ + // nothing todo +} + +QCLuceneQuery* QCLuceneMultiFieldQueryParser::parse(const QString &query, + const QStringList &fieldList, + QCLuceneAnalyzer &analyzer) +{ + QCLuceneBooleanQuery *retValue = new QCLuceneBooleanQuery(); + foreach (const QString &field, fieldList) { + QCLuceneQuery *q = QCLuceneQueryParser::parse(query, field, analyzer); + if (!q) { + delete retValue; + retValue = 0; break; + } else { + retValue->add(q, true, false, false); + } + } + + return retValue; +} + +QCLuceneQuery* QCLuceneMultiFieldQueryParser::parse(const QString &query, + const QStringList &fieldList, + QList<FieldFlags> flags, + QCLuceneAnalyzer &analyzer) +{ + QCLuceneBooleanQuery *retValue = new QCLuceneBooleanQuery(); + qint32 i = 0; + foreach (const QString &field, fieldList) { + QCLuceneQuery *q = QCLuceneQueryParser::parse(query, field, analyzer); + if (q) { + qint32 flag = flags.at(i); + switch (flag) { + case QCLuceneMultiFieldQueryParser::REQUIRED_FIELD: { + retValue->add(q, true, true, false); + } break; + + case QCLuceneMultiFieldQueryParser::PROHIBITED_FIELD: { + retValue->add(q, true, false, true); + } break; + + default: { + retValue->add(q, true, false, false); + } break; + } + + ++i; + } else { + delete retValue; + retValue = 0; break; + } + } + return retValue; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qqueryparser_p.h b/tools/assistant/lib/fulltextsearch/qqueryparser_p.h new file mode 100644 index 0000000..976ee63 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qqueryparser_p.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QQUERYPARSER_P_H +#define QQUERYPARSER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qreader_p.h" +#include "qanalyzer_p.h" +#include "qclucene_global_p.h" + +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(queryParser) + class QueryParser; +CL_NS_END +CL_NS_USE(queryParser) + +QT_BEGIN_NAMESPACE + +class QCLuceneQuery; +class QCLuceneMultiFieldQueryParser; + +class QHELP_EXPORT QCLuceneQueryParserPrivate : public QSharedData +{ +public: + QCLuceneQueryParserPrivate(); + QCLuceneQueryParserPrivate(const QCLuceneQueryParserPrivate &other); + + ~QCLuceneQueryParserPrivate(); + + QueryParser *queryParser; + bool deleteCLuceneQueryParser; + +private: + QCLuceneQueryParserPrivate &operator=(const QCLuceneQueryParserPrivate &other); +}; + +class QHELP_EXPORT QCLuceneQueryParser +{ +public: + QCLuceneQueryParser(const QString &field, QCLuceneAnalyzer &analyzer); + virtual ~QCLuceneQueryParser(); + + QCLuceneQuery* parse(const QString &query); + QCLuceneQuery* parse(QCLuceneReader &reader); + static QCLuceneQuery* parse(const QString &query, const QString &field, + QCLuceneAnalyzer &analyzer); + QCLuceneAnalyzer getAnalyzer(); + QString getField(); + +protected: + friend class QCLuceneMultiFieldQueryParser; + QSharedDataPointer<QCLuceneQueryParserPrivate> d; + +private: + QString field; + QCLuceneAnalyzer analyzer; +}; + +class QHELP_EXPORT QCLuceneMultiFieldQueryParser : public QCLuceneQueryParser +{ +public: + enum FieldFlags { + NORMAL_FIELD = 0, + REQUIRED_FIELD = 1, + PROHIBITED_FIELD = 2 + }; + + QCLuceneMultiFieldQueryParser(const QStringList &fieldList, + QCLuceneAnalyzer &analyzer); + ~QCLuceneMultiFieldQueryParser(); + + static QCLuceneQuery *parse(const QString &query, const QStringList &fieldList, + QCLuceneAnalyzer &analyzer); + static QCLuceneQuery *parse(const QString &query, const QStringList &fieldList, + QList<FieldFlags> flags, QCLuceneAnalyzer &analyzer); +}; + +QT_END_NAMESPACE + +#endif // QQUERYPARSER_P_H diff --git a/tools/assistant/lib/fulltextsearch/qreader.cpp b/tools/assistant/lib/fulltextsearch/qreader.cpp new file mode 100644 index 0000000..792056d --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qreader.cpp @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qreader_p.h" +#include "qclucene_global_p.h" + +#include <CLucene.h> +#include <CLucene/util/Reader.h> + +QT_BEGIN_NAMESPACE + +QCLuceneReaderPrivate::QCLuceneReaderPrivate() + : QSharedData() +{ + reader = 0; + deleteCLuceneReader = true; +} + +QCLuceneReaderPrivate::QCLuceneReaderPrivate(const QCLuceneReaderPrivate &other) + : QSharedData() +{ + reader = _CL_POINTER(other.reader); +} + +QCLuceneReaderPrivate::~QCLuceneReaderPrivate() +{ + if (deleteCLuceneReader) + _CLDECDELETE(reader); +} + + +QCLuceneReader::QCLuceneReader() + : d(new QCLuceneReaderPrivate()) +{ + // nothing todo +} + +QCLuceneReader::~QCLuceneReader() +{ + // nothing todo +} + + +QCLuceneStringReader::QCLuceneStringReader(const QString &value) + : QCLuceneReader() + , string(QStringToTChar(value)) +{ + d->reader = new lucene::util::StringReader(string); +} + +QCLuceneStringReader::QCLuceneStringReader(const QString &value, qint32 length) + : QCLuceneReader() + , string(QStringToTChar(value)) +{ + d->reader = new lucene::util::StringReader(string, int32_t(length)); +} + +QCLuceneStringReader::QCLuceneStringReader(const QString &value, qint32 length, + bool copyData) + : QCLuceneReader() + , string(QStringToTChar(value)) +{ + d->reader = new lucene::util::StringReader(string, int32_t(length), copyData); +} + +QCLuceneStringReader::~QCLuceneStringReader() +{ + delete [] string; +} + + +QCLuceneFileReader::QCLuceneFileReader(const QString &path, const QString &encoding, + qint32 cacheLength, qint32 cacheBuffer) + : QCLuceneReader() +{ + const QByteArray tmpPath = path.toLocal8Bit(); + const QByteArray tmpEncoding = encoding.toAscii(); + d->reader = new lucene::util::FileReader(tmpPath.constData(), + tmpEncoding.constData(), int32_t(cacheLength), int32_t(cacheBuffer)); +} + +QCLuceneFileReader::~QCLuceneFileReader() +{ + // nothing todo +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qreader_p.h b/tools/assistant/lib/fulltextsearch/qreader_p.h new file mode 100644 index 0000000..77c8007 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qreader_p.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QREADER_P_H +#define QREADER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qclucene_global_p.h" + +#include <QtCore/QString> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(util) + class Reader; +CL_NS_END +CL_NS_USE(util) + +QT_BEGIN_NAMESPACE + +class QCLuceneField; +class QCLuceneAnalyzer; +class QCLuceneDocument; +class QCLuceneQueryParser; +class QCLuceneStandardTokenizer; + +class QHELP_EXPORT QCLuceneReaderPrivate : public QSharedData +{ +public: + QCLuceneReaderPrivate(); + QCLuceneReaderPrivate(const QCLuceneReaderPrivate &other); + + ~QCLuceneReaderPrivate(); + + Reader* reader; + bool deleteCLuceneReader; + +private: + QCLuceneReaderPrivate &operator=(const QCLuceneReaderPrivate &other); +}; + +class QHELP_EXPORT QCLuceneReader +{ +public: + QCLuceneReader(); + virtual ~QCLuceneReader(); + +protected: + friend class QCLuceneField; + friend class QCLuceneAnalyzer; + friend class QCLuceneDocument; + friend class QCLuceneQueryParser; + friend class QCLuceneStandardTokenizer; + QSharedDataPointer<QCLuceneReaderPrivate> d; +}; + +class QCLuceneStringReader : public QCLuceneReader +{ +public: + QCLuceneStringReader(const QString &value); + QCLuceneStringReader(const QString &value, qint32 length); + QCLuceneStringReader(const QString &value, qint32 length, bool copyData); + + ~QCLuceneStringReader(); + +private: + TCHAR *string; +}; + +class QHELP_EXPORT QCLuceneFileReader : public QCLuceneReader +{ +public: + QCLuceneFileReader(const QString &path, const QString &encoding, + qint32 cacheLength = 13, qint32 cacheBuffer = 14); + ~QCLuceneFileReader(); +}; + +QT_END_NAMESPACE + +#endif // QREADER_P_H diff --git a/tools/assistant/lib/fulltextsearch/qsearchable.cpp b/tools/assistant/lib/fulltextsearch/qsearchable.cpp new file mode 100644 index 0000000..2d76b02 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qsearchable.cpp @@ -0,0 +1,195 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qsearchable_p.h" + +#include <CLucene.h> +#include <CLucene/search/SearchHeader.h> + +QT_BEGIN_NAMESPACE + +QCLuceneSearchablePrivate::QCLuceneSearchablePrivate() + : QSharedData() +{ + searchable = 0; + deleteCLuceneSearchable = true; +} + +QCLuceneSearchablePrivate::QCLuceneSearchablePrivate(const QCLuceneSearchablePrivate &other) + : QSharedData() +{ + searchable = _CL_POINTER(other.searchable); +} + +QCLuceneSearchablePrivate::~QCLuceneSearchablePrivate() +{ + if (deleteCLuceneSearchable) + _CLDECDELETE(searchable); +} + + +QCLuceneSearchable::QCLuceneSearchable() + : d(new QCLuceneSearchablePrivate()) +{ + // nothing todo +} + +QCLuceneSearchable::~QCLuceneSearchable() +{ + // nothing todo +} + + +QCLuceneSearcher::QCLuceneSearcher() + : QCLuceneSearchable() +{ + // nothing todo +} + +QCLuceneSearcher::~QCLuceneSearcher() +{ + // nothing todo; +} + +QCLuceneHits QCLuceneSearcher::search(const QCLuceneQuery &query) +{ + return search(query, QCLuceneFilter()); +} + +QCLuceneHits QCLuceneSearcher::search(const QCLuceneQuery &query, + const QCLuceneFilter &filter) +{ + return QCLuceneHits(*this, query, filter); +} + +QCLuceneHits QCLuceneSearcher::search(const QCLuceneQuery &query, + const QCLuceneSort &sort) +{ + return QCLuceneHits(*this, query, QCLuceneFilter(), sort); +} + +QCLuceneHits QCLuceneSearcher::search(const QCLuceneQuery &query, + const QCLuceneFilter &filter, + const QCLuceneSort &sort) +{ + return QCLuceneHits(*this, query, filter, sort); +} + + +QCLuceneIndexSearcher::QCLuceneIndexSearcher(const QString &path) + : QCLuceneSearcher() +{ + lucene::search::IndexSearcher *searcher = + new lucene::search::IndexSearcher(path); + + reader.d->reader = searcher->getReader(); + reader.d->deleteCLuceneIndexReader = false; + + d->searchable = searcher; +} + +QCLuceneIndexSearcher::QCLuceneIndexSearcher(const QCLuceneIndexReader &reader) + : QCLuceneSearcher() + , reader(reader) +{ + d->searchable = new lucene::search::IndexSearcher(reader.d->reader); +} + +QCLuceneIndexSearcher::~QCLuceneIndexSearcher() +{ + // nothing todo +} + +void QCLuceneIndexSearcher::close() +{ + d->searchable->close(); +} + +qint32 QCLuceneIndexSearcher::maxDoc() const +{ + return qint32(d->searchable->maxDoc()); +} + +QCLuceneIndexReader QCLuceneIndexSearcher::getReader() +{ + return reader; +} + +bool QCLuceneIndexSearcher::doc(qint32 i, QCLuceneDocument &document) +{ + return d->searchable->doc(int32_t(i), document.d->document); +} + + +QCLuceneMultiSearcher::QCLuceneMultiSearcher(const QList<QCLuceneSearchable> searchables) +: QCLuceneSearcher() +{ + lucene::search::Searchable** list= + _CL_NEWARRAY(lucene::search::Searchable*, searchables.count()); + + d->searchable = new lucene::search::MultiSearcher(list); + + _CLDELETE_ARRAY(list); +} + +QCLuceneMultiSearcher::~QCLuceneMultiSearcher() +{ + // nothing todo +} + +void QCLuceneMultiSearcher::close() +{ + d->searchable->close(); +} + +qint32 QCLuceneMultiSearcher::maxDoc() const +{ + return qint32(d->searchable->maxDoc()); +} + +qint32 QCLuceneMultiSearcher::subDoc(qint32 index) const +{ + lucene::search::MultiSearcher *searcher = + static_cast<lucene::search::MultiSearcher*> (d->searchable); + + if (searcher == 0) + return 0; + + return qint32(searcher->subDoc(int32_t(index))); +} + +qint32 QCLuceneMultiSearcher::subSearcher(qint32 index) const +{ + lucene::search::MultiSearcher *searcher = + static_cast<lucene::search::MultiSearcher*> (d->searchable); + + if (searcher == 0) + return 0; + + return qint32(searcher->subSearcher(int32_t(index))); +} + +qint32 QCLuceneMultiSearcher::searcherIndex(qint32 index) const +{ + lucene::search::MultiSearcher *searcher = + static_cast<lucene::search::MultiSearcher*> (d->searchable); + + if (searcher == 0) + return 0; + + return qint32(searcher->searcherIndex(int32_t(index))); +} + +bool QCLuceneMultiSearcher::doc(qint32 i, QCLuceneDocument &document) +{ + return d->searchable->doc(int32_t(i), document.d->document); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qsearchable_p.h b/tools/assistant/lib/fulltextsearch/qsearchable_p.h new file mode 100644 index 0000000..8e4da44 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qsearchable_p.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QSEARCHABLE_P_H +#define QSEARCHABLE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhits_p.h" +#include "qsort_p.h" +#include "qquery_p.h" +#include "qfilter_p.h" +#include "qdocument_p.h" +#include "qindexreader_p.h" +#include "qclucene_global_p.h" + +#include <QtCore/QList> +#include <QtCore/QString> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(search) + class Searcher; +CL_NS_END +CL_NS_USE(search) + +QT_BEGIN_NAMESPACE + +class QCLuceneHits; +class QCLuceneSearcher; +class QCLuceneIndexSearcher; +class QCLuceneMultiSearcher; + +class QHELP_EXPORT QCLuceneSearchablePrivate : public QSharedData +{ +public: + QCLuceneSearchablePrivate(); + QCLuceneSearchablePrivate(const QCLuceneSearchablePrivate &other); + + ~QCLuceneSearchablePrivate(); + + Searcher *searchable; + bool deleteCLuceneSearchable; + +private: + QCLuceneSearchablePrivate &operator=(const QCLuceneSearchablePrivate &other); +}; + +class QHELP_EXPORT QCLuceneSearchable +{ +public: + virtual ~QCLuceneSearchable(); + +protected: + friend class QCLuceneSearcher; + friend class QCLuceneIndexSearcher; + friend class QCLuceneMultiSearcher; + QSharedDataPointer<QCLuceneSearchablePrivate> d; + +private: + QCLuceneSearchable(); +}; + +class QHELP_EXPORT QCLuceneSearcher : public QCLuceneSearchable +{ +public: + QCLuceneSearcher(); + virtual ~QCLuceneSearcher(); + + QCLuceneHits search(const QCLuceneQuery &query); + QCLuceneHits search(const QCLuceneQuery &query, const QCLuceneFilter &filter); + QCLuceneHits search(const QCLuceneQuery &query, const QCLuceneSort &sort); + QCLuceneHits search(const QCLuceneQuery &query, const QCLuceneFilter &filter, + const QCLuceneSort &sort); + +protected: + friend class QCLuceneHits; +}; + +class QHELP_EXPORT QCLuceneIndexSearcher : public QCLuceneSearcher +{ +public: + QCLuceneIndexSearcher(const QString &path); + QCLuceneIndexSearcher(const QCLuceneIndexReader &reader); + ~QCLuceneIndexSearcher(); + + void close(); + qint32 maxDoc() const; + QCLuceneIndexReader getReader(); + bool doc(qint32 i, QCLuceneDocument &document); + +private: + QCLuceneIndexReader reader; +}; + +class QHELP_EXPORT QCLuceneMultiSearcher : public QCLuceneSearcher +{ +public: + QCLuceneMultiSearcher(const QList<QCLuceneSearchable> searchables); + ~QCLuceneMultiSearcher(); + + void close(); + qint32 maxDoc() const; + qint32 subDoc(qint32 index) const; + qint32 subSearcher(qint32 index) const; + qint32 searcherIndex(qint32 index) const; + bool doc(qint32 i, QCLuceneDocument &document); +}; + +QT_END_NAMESPACE + +#endif // QSEARCHABLE_P_H diff --git a/tools/assistant/lib/fulltextsearch/qsort.cpp b/tools/assistant/lib/fulltextsearch/qsort.cpp new file mode 100644 index 0000000..06d7276 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qsort.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qsort_p.h" +#include "qclucene_global_p.h" + +#include <CLucene.h> +#include <CLucene/search/Sort.h> + +QT_BEGIN_NAMESPACE + +QCLuceneSortPrivate::QCLuceneSortPrivate() + : QSharedData() +{ + sort = 0; + deleteCLuceneSort = true; +} + +QCLuceneSortPrivate::QCLuceneSortPrivate (const QCLuceneSortPrivate &other) + : QSharedData() +{ + sort = _CL_POINTER(other.sort); +} + +QCLuceneSortPrivate::~QCLuceneSortPrivate() +{ + if (deleteCLuceneSort) + _CLDECDELETE(sort); +} + + +QCLuceneSort::QCLuceneSort() + : d(new QCLuceneSortPrivate()) +{ + d->sort = new lucene::search::Sort(); +} + +QCLuceneSort::QCLuceneSort(const QStringList &fieldNames) + : d(new QCLuceneSortPrivate()) +{ + d->sort = new lucene::search::Sort(); + setSort(fieldNames); +} + +QCLuceneSort::QCLuceneSort(const QString &field, bool reverse) + : d(new QCLuceneSortPrivate()) +{ + d->sort = new lucene::search::Sort(); + setSort(field, reverse); +} + +QCLuceneSort::~QCLuceneSort() +{ + // nothing todo +} + +QString QCLuceneSort::toString() const +{ + return TCharToQString(d->sort->toString()); +} + +void QCLuceneSort::setSort(const QStringList &fieldNames) +{ + TCHAR **nameArray = new TCHAR*[fieldNames.count()]; + for (int i = 0; i < fieldNames.count(); ++i) + nameArray[i] = QStringToTChar(fieldNames.at(i)); + + d->sort->setSort((const TCHAR**)nameArray); + + for (int i = 0; i < fieldNames.count(); ++i) + delete [] nameArray[i]; + delete nameArray; +} + +void QCLuceneSort::setSort(const QString &field, bool reverse) +{ + TCHAR *name = QStringToTChar(field); + d->sort->setSort(name, reverse); + delete [] name; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qsort_p.h b/tools/assistant/lib/fulltextsearch/qsort_p.h new file mode 100644 index 0000000..5ec2a06 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qsort_p.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QSORT_P_H +#define QSORT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qclucene_global_p.h" + +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(search) + class Sort; +CL_NS_END +CL_NS_USE(search) + +QT_BEGIN_NAMESPACE + +class QCLuceneHits; +class QCLuceneField; + +class QHELP_EXPORT QCLuceneSortPrivate : public QSharedData +{ +public: + QCLuceneSortPrivate(); + QCLuceneSortPrivate (const QCLuceneSortPrivate &other); + + ~QCLuceneSortPrivate(); + + Sort *sort; + bool deleteCLuceneSort; + +private: + QCLuceneSortPrivate &operator=(const QCLuceneSortPrivate &other); +}; + +class QHELP_EXPORT QCLuceneSort +{ +public: + QCLuceneSort(); + QCLuceneSort(const QStringList &fieldNames); + QCLuceneSort(const QString &field, bool reverse = false); + + virtual ~QCLuceneSort(); + + QString toString() const; + void setSort(const QStringList &fieldNames); + void setSort(const QString &field, bool reverse = false); + +protected: + friend class QCLuceneHits; + QSharedDataPointer<QCLuceneSortPrivate> d; +}; + +QT_END_NAMESPACE + +#endif // QSORT_P_H diff --git a/tools/assistant/lib/fulltextsearch/qterm.cpp b/tools/assistant/lib/fulltextsearch/qterm.cpp new file mode 100644 index 0000000..156586f --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qterm.cpp @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qterm_p.h" +#include "qclucene_global_p.h" + +#include <CLucene.h> +#include <CLucene/index/IndexReader.h> + +QT_BEGIN_NAMESPACE + +QCLuceneTermPrivate::QCLuceneTermPrivate() + : QSharedData() +{ + term = 0; + deleteCLuceneTerm = true; +} + +QCLuceneTermPrivate::QCLuceneTermPrivate(const QCLuceneTermPrivate &other) + : QSharedData() +{ + term = _CL_POINTER(other.term); +} + +QCLuceneTermPrivate::~QCLuceneTermPrivate() +{ + if (deleteCLuceneTerm) + _CLDECDELETE(term); +} + + +QCLuceneTerm::QCLuceneTerm() + : d(new QCLuceneTermPrivate()) +{ + d->term = new lucene::index::Term(); +} + +QCLuceneTerm::QCLuceneTerm(const QString &field, const QString &text) + : d(new QCLuceneTermPrivate()) +{ + TCHAR *fieldName = QStringToTChar(field); + TCHAR *termText = QStringToTChar(text); + + d->term = new lucene::index::Term(fieldName, termText); + + delete [] fieldName; + delete [] termText; +} + +QCLuceneTerm::QCLuceneTerm(const QCLuceneTerm &fieldTerm, const QString &text) + : d(new QCLuceneTermPrivate()) +{ + TCHAR *termText = QStringToTChar(text); + d->term = new lucene::index::Term(fieldTerm.d->term, termText); + delete [] termText; +} + +QCLuceneTerm::~QCLuceneTerm() +{ + // nothing todo +} + +QString QCLuceneTerm::field() const +{ + return TCharToQString(d->term->field()); +} + +QString QCLuceneTerm::text() const +{ + return TCharToQString(d->term->text()); +} + +void QCLuceneTerm::set(const QString &field, const QString &text) +{ + set(field, text, true); +} + +void QCLuceneTerm::set(const QCLuceneTerm &fieldTerm, const QString &text) +{ + set(fieldTerm.field(), text, false); +} + +void QCLuceneTerm::set(const QString &field, const QString &text, bool internField) +{ + TCHAR *fieldName = QStringToTChar(field); + TCHAR *termText = QStringToTChar(text); + + d->term->set(fieldName, termText, internField); + + delete [] fieldName; + delete [] termText; +} + +bool QCLuceneTerm::equals(const QCLuceneTerm &other) const +{ + return d->term->equals(other.d->term); +} + +qint32 QCLuceneTerm::compareTo(const QCLuceneTerm &other) const +{ + return quint32(d->term->compareTo(other.d->term)); +} + +QString QCLuceneTerm::toString() const +{ + return TCharToQString(d->term->toString()); +} + +quint32 QCLuceneTerm::hashCode() const +{ + return quint32(d->term->hashCode()); +} + +quint32 QCLuceneTerm::textLength() const +{ + return quint32(d->term->textLength()); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qterm_p.h b/tools/assistant/lib/fulltextsearch/qterm_p.h new file mode 100644 index 0000000..474c909 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qterm_p.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QTERM_P_H +#define QTERM_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qclucene_global_p.h" + +#include <QtCore/QSharedData> +#include <QtCore/QString> +#include <QtCore/QSharedDataPointer> + +CL_NS_DEF(index) + class Term; +CL_NS_END +CL_NS_USE(index) + +QT_BEGIN_NAMESPACE + +class QCLuceneTermQuery; +class QCLuceneRangeQuery; +class QCLucenePrefixQuery; +class QCLuceneIndexReader; +class QCLucenePhraseQuery; + +class QHELP_EXPORT QCLuceneTermPrivate : public QSharedData +{ +public: + QCLuceneTermPrivate(); + QCLuceneTermPrivate(const QCLuceneTermPrivate &other); + + ~QCLuceneTermPrivate(); + + Term *term; + bool deleteCLuceneTerm; + +private: + QCLuceneTermPrivate &operator=(const QCLuceneTermPrivate &other); +}; + +class QHELP_EXPORT QCLuceneTerm +{ +public: + QCLuceneTerm(); + QCLuceneTerm(const QString &field, const QString &text); + QCLuceneTerm(const QCLuceneTerm &fieldTerm, const QString &text); + + virtual ~QCLuceneTerm(); + + QString field() const; + QString text() const; + + void set(const QString &field, const QString &text); + void set(const QCLuceneTerm &fieldTerm, const QString &text); + void set(const QString &field, const QString &text, bool internField); + + bool equals(const QCLuceneTerm &other) const; + qint32 compareTo(const QCLuceneTerm &other) const; + + QString toString() const; + quint32 hashCode() const; + quint32 textLength() const; + +protected: + friend class QCLuceneTermQuery; + friend class QCLuceneRangeQuery; + friend class QCLucenePrefixQuery; + friend class QCLuceneIndexReader; + friend class QCLucenePhraseQuery; + QSharedDataPointer<QCLuceneTermPrivate> d; +}; + +QT_END_NAMESPACE + +#endif // QTERM_P_H diff --git a/tools/assistant/lib/fulltextsearch/qtoken.cpp b/tools/assistant/lib/fulltextsearch/qtoken.cpp new file mode 100644 index 0000000..fa5d62a --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qtoken.cpp @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qtoken_p.h" +#include "qclucene_global_p.h" + +#include <CLucene.h> +#include <CLucene/analysis/AnalysisHeader.h> + +QT_BEGIN_NAMESPACE + +QCLuceneTokenPrivate::QCLuceneTokenPrivate() + : QSharedData() +{ + token = 0; + deleteCLuceneToken = true; +} + +QCLuceneTokenPrivate::QCLuceneTokenPrivate(const QCLuceneTokenPrivate &other) + : QSharedData() +{ + token = _CL_POINTER(other.token); +} + +QCLuceneTokenPrivate::~QCLuceneTokenPrivate() +{ + if (deleteCLuceneToken) + _CLDECDELETE(token); +} + + +QCLuceneToken::QCLuceneToken() + : d(new QCLuceneTokenPrivate()) + , tokenText(0) + , tokenType(0) +{ + d->token = new lucene::analysis::Token(); +} + +QCLuceneToken::QCLuceneToken(const QString &text, qint32 startOffset, + qint32 endOffset, const QString &defaultTyp) + : d(new QCLuceneTokenPrivate()) + , tokenText(QStringToTChar(text)) + , tokenType(QStringToTChar(defaultTyp)) +{ + d->token = new lucene::analysis::Token(tokenText, int32_t(startOffset), + int32_t(endOffset), tokenType); +} + +QCLuceneToken::~QCLuceneToken() +{ + delete [] tokenText; + delete [] tokenType; +} + +quint32 QCLuceneToken::bufferLength() const +{ + return quint32(d->token->bufferLength()); +} + +void QCLuceneToken::growBuffer(quint32 size) +{ + d->token->growBuffer(size_t(size)); +} + +qint32 QCLuceneToken::positionIncrement() const +{ + return qint32(d->token->getPositionIncrement()); +} + +void QCLuceneToken::setPositionIncrement(qint32 positionIncrement) +{ + d->token->setPositionIncrement(int32_t(positionIncrement)); +} + +QString QCLuceneToken::termText() const +{ + return TCharToQString(d->token->termText()); +} + +void QCLuceneToken::setTermText(const QString &text) +{ + delete [] tokenText; + tokenText = QStringToTChar(text); + d->token->setText(tokenText); +} + +quint32 QCLuceneToken::termTextLength() const +{ + return quint32(d->token->termTextLength()); +} + +void QCLuceneToken::resetTermTextLength() const +{ + d->token->resetTermTextLen(); +} + +qint32 QCLuceneToken::startOffset() const +{ + return quint32(d->token->startOffset()); +} + +void QCLuceneToken::setStartOffset(qint32 value) +{ + d->token->setStartOffset(int32_t(value)); +} + +qint32 QCLuceneToken::endOffset() const +{ + return quint32(d->token->endOffset()); +} + +void QCLuceneToken::setEndOffset(qint32 value) +{ + d->token->setEndOffset(int32_t(value)); +} + +QString QCLuceneToken::type() const +{ + return TCharToQString(d->token->type()); +} + +void QCLuceneToken::setType(const QString &type) +{ + delete [] tokenType; + tokenType = QStringToTChar(type); + d->token->setType(tokenType); +} + +QString QCLuceneToken::toString() const +{ + return TCharToQString(d->token->toString()); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qtoken_p.h b/tools/assistant/lib/fulltextsearch/qtoken_p.h new file mode 100644 index 0000000..1802f99 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qtoken_p.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QTOKEN_P_H +#define QTOKEN_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qclucene_global_p.h" + +#include <QtCore/QString> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(analysis) + class Token; +CL_NS_END +CL_NS_USE(analysis) + +QT_BEGIN_NAMESPACE + +class QCLuceneTokenizer; +class QCLuceneTokenStream; +class QCLuceneStandardTokenizer; + +class QHELP_EXPORT QCLuceneTokenPrivate : public QSharedData +{ +public: + QCLuceneTokenPrivate(); + QCLuceneTokenPrivate(const QCLuceneTokenPrivate &other); + + ~QCLuceneTokenPrivate(); + + Token *token; + bool deleteCLuceneToken; + +private: + QCLuceneTokenPrivate &operator=(const QCLuceneTokenPrivate &other); +}; + +class QHELP_EXPORT QCLuceneToken +{ +public: + QCLuceneToken(); + QCLuceneToken(const QString &text, qint32 startOffset, + qint32 endOffset, const QString &defaultTyp = QLatin1String("word")); + + virtual ~QCLuceneToken(); + + void set(const QString &text, qint32 startOffset, + qint32 endOffset, const QString &defaultTyp = QLatin1String("word")); + + quint32 bufferLength() const; + void growBuffer(quint32 size); + + qint32 positionIncrement() const; + void setPositionIncrement(qint32 positionIncrement); + + QString termText() const; + void setTermText(const QString &text); + + quint32 termTextLength() const; + void resetTermTextLength() const; + + qint32 startOffset() const; + void setStartOffset(qint32 value); + + qint32 endOffset() const; + void setEndOffset(qint32 value); + + QString type() const; + void setType(const QString &type); + + QString toString() const; + +protected: + friend class QCLuceneTokenizer; + friend class QCLuceneTokenStream; + friend class QCLuceneStandardTokenizer; + QSharedDataPointer<QCLuceneTokenPrivate> d; + +private: + TCHAR *tokenText; + TCHAR *tokenType; +}; + +QT_END_NAMESPACE + +#endif // QTOKEN_P_H diff --git a/tools/assistant/lib/fulltextsearch/qtokenizer.cpp b/tools/assistant/lib/fulltextsearch/qtokenizer.cpp new file mode 100644 index 0000000..9a07387 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qtokenizer.cpp @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qtokenizer_p.h" +#include "qclucene_global_p.h" + +#include <CLucene.h> +#include <CLucene/analysis/AnalysisHeader.h> + +QT_BEGIN_NAMESPACE + +QCLuceneTokenizer::QCLuceneTokenizer() + : QCLuceneTokenStream() +{ + // nothing todo +} + +QCLuceneTokenizer::QCLuceneTokenizer(const QCLuceneReader &reader) + : QCLuceneTokenStream() + , reader(reader) +{ + // nothing todo +} + +QCLuceneTokenizer::~QCLuceneTokenizer() +{ + close(); +} + +void QCLuceneTokenizer::close() +{ + d->tokenStream->close(); +} + +bool QCLuceneTokenizer::next(QCLuceneToken &token) +{ + return d->tokenStream->next(token.d->token); +} + + +QCLuceneStandardTokenizer::QCLuceneStandardTokenizer(const QCLuceneReader &reader) + : QCLuceneTokenizer(reader) +{ + d->tokenStream = + new lucene::analysis::standard::StandardTokenizer(reader.d->reader); +} + +QCLuceneStandardTokenizer::~QCLuceneStandardTokenizer() +{ + // nothing todo +} + +bool QCLuceneStandardTokenizer::readApostrophe(const QString &string, + QCLuceneToken &token) +{ + lucene::analysis::standard::StandardTokenizer *stdTokenizer = + static_cast<lucene::analysis::standard::StandardTokenizer*> (d->tokenStream); + + if (stdTokenizer == 0) + return false; + + TCHAR* value = QStringToTChar(string); + lucene::util::StringBuffer buffer(value); + bool retValue = stdTokenizer->ReadApostrophe(&buffer, token.d->token); + delete [] value; + + return retValue; +} + +bool QCLuceneStandardTokenizer::readAt(const QString &string, QCLuceneToken &token) +{ + lucene::analysis::standard::StandardTokenizer *stdTokenizer = + static_cast<lucene::analysis::standard::StandardTokenizer*> (d->tokenStream); + + if (stdTokenizer == 0) + return false; + + TCHAR* value = QStringToTChar(string); + lucene::util::StringBuffer buffer(value); + bool retValue = stdTokenizer->ReadAt(&buffer, token.d->token); + delete [] value; + + return retValue; +} + +bool QCLuceneStandardTokenizer::readCompany(const QString &string, + QCLuceneToken &token) +{ + lucene::analysis::standard::StandardTokenizer *stdTokenizer = + static_cast<lucene::analysis::standard::StandardTokenizer*> (d->tokenStream); + + if (stdTokenizer == 0) + return false; + + TCHAR* value = QStringToTChar(string); + lucene::util::StringBuffer buffer(value); + bool retValue = stdTokenizer->ReadCompany(&buffer, token.d->token); + delete [] value; + + return retValue; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/fulltextsearch/qtokenizer_p.h b/tools/assistant/lib/fulltextsearch/qtokenizer_p.h new file mode 100644 index 0000000..1e7916c --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qtokenizer_p.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QTOKENIZER_P_H +#define QTOKENIZER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qtoken_p.h" +#include "qreader_p.h" +#include "qtokenstream_p.h" +#include "qclucene_global_p.h" + +#include <QtCore/QChar> +#include <QtCore/QString> + +QT_BEGIN_NAMESPACE + +class QHELP_EXPORT QCLuceneTokenizer : public QCLuceneTokenStream +{ +public: + QCLuceneTokenizer(const QCLuceneReader &reader); + virtual ~QCLuceneTokenizer(); + + void close(); + bool next(QCLuceneToken &token); + +protected: + friend class QCLuceneStandardTokenizer; + +private: + QCLuceneTokenizer(); + QCLuceneReader reader; +}; + +class QHELP_EXPORT QCLuceneStandardTokenizer : public QCLuceneTokenizer +{ +public: + QCLuceneStandardTokenizer(const QCLuceneReader &reader); + ~QCLuceneStandardTokenizer(); + + bool readApostrophe(const QString &string, QCLuceneToken &token); + bool readAt(const QString &string, QCLuceneToken &token); + bool readCompany(const QString &string, QCLuceneToken &token); +}; + +class QCLuceneCharTokenizer : public QCLuceneTokenizer +{ + +}; + +class QCLuceneLetterTokenizer : public QCLuceneCharTokenizer +{ + +}; + +class QCLuceneLowerCaseTokenizer : public QCLuceneLetterTokenizer +{ + +}; + +class QCLuceneWhitespaceTokenizer : public QCLuceneCharTokenizer +{ + +}; + +class QCLuceneKeywordTokenizer : public QCLuceneTokenizer +{ + +}; + +QT_END_NAMESPACE + +#endif // QTOKENIZER_P_H diff --git a/tools/assistant/lib/fulltextsearch/qtokenstream.cpp b/tools/assistant/lib/fulltextsearch/qtokenstream.cpp new file mode 100644 index 0000000..957a0c2 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qtokenstream.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#include "qtokenstream_p.h" + +#include <CLucene.h> +#include <CLucene/analysis/AnalysisHeader.h> + +QT_BEGIN_NAMESPACE + +QCLuceneTokenStreamPrivate::QCLuceneTokenStreamPrivate() + : QSharedData() +{ + tokenStream = 0; + deleteCLuceneTokenStream = true; +} + +QCLuceneTokenStreamPrivate::QCLuceneTokenStreamPrivate(const QCLuceneTokenStreamPrivate &other) + : QSharedData() +{ + tokenStream = _CL_POINTER(other.tokenStream); +} + +QCLuceneTokenStreamPrivate::~QCLuceneTokenStreamPrivate() +{ + if (deleteCLuceneTokenStream) + _CLDECDELETE(tokenStream); +} + + +QCLuceneTokenStream::QCLuceneTokenStream() + : d(new QCLuceneTokenStreamPrivate()) +{ + // nothing todo +} + +QCLuceneTokenStream::~QCLuceneTokenStream() +{ + // nothing todo +} + +void QCLuceneTokenStream::close() +{ + d->tokenStream->close(); +} + +bool QCLuceneTokenStream::next(QCLuceneToken &token) +{ + return d->tokenStream->next(token.d->token); +} + +QT_END_NAMESPACE
\ No newline at end of file diff --git a/tools/assistant/lib/fulltextsearch/qtokenstream_p.h b/tools/assistant/lib/fulltextsearch/qtokenstream_p.h new file mode 100644 index 0000000..ef6e715 --- /dev/null +++ b/tools/assistant/lib/fulltextsearch/qtokenstream_p.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QCLucene library and is distributable under +** the terms of the LGPL license as specified in the license.txt file. +** +****************************************************************************/ + +#ifndef QTOKENSTREAM_P_H +#define QTOKENSTREAM_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qtoken_p.h" +#include "qclucene_global_p.h" + +#include <QtCore/QString> +#include <QtCore/QSharedDataPointer> +#include <QtCore/QSharedData> + +CL_NS_DEF(analysis) + class TokenStream; +CL_NS_END +CL_NS_USE(analysis) + +QT_BEGIN_NAMESPACE + +class QCLuceneAnalyzer; +class QCLuceneTokenizer; +class QCLuceneStopAnalyzer; +class QCLuceneSimpleAnalyzer; +class QCLuceneKeywordAnalyzer; +class QCLuceneStandardAnalyzer; +class QCLuceneWhitespaceAnalyzer; +class QCLucenePerFieldAnalyzerWrapper; + +class QHELP_EXPORT QCLuceneTokenStreamPrivate : public QSharedData +{ +public: + QCLuceneTokenStreamPrivate(); + QCLuceneTokenStreamPrivate(const QCLuceneTokenStreamPrivate &other); + + ~QCLuceneTokenStreamPrivate(); + + TokenStream *tokenStream; + bool deleteCLuceneTokenStream; + +private: + QCLuceneTokenStreamPrivate &operator=(const QCLuceneTokenStreamPrivate &other); +}; + +class QHELP_EXPORT QCLuceneTokenStream +{ +public: + virtual ~QCLuceneTokenStream(); + + void close(); + bool next(QCLuceneToken &token); + +protected: + friend class QCLuceneAnalyzer; + friend class QCLuceneTokenizer; + friend class QCLuceneStopAnalyzer; + friend class QCLuceneSimpleAnalyzer; + friend class QCLuceneKeywordAnalyzer; + friend class QCLuceneStandardAnalyzer; + friend class QCLuceneWhitespaceAnalyzer; + friend class QCLucenePerFieldAnalyzerWrapper; + QSharedDataPointer<QCLuceneTokenStreamPrivate> d; + +private: + QCLuceneTokenStream(); +}; + +QT_END_NAMESPACE + +#endif // QTOKENSTREAM_P_H diff --git a/tools/assistant/lib/helpsystem.qrc b/tools/assistant/lib/helpsystem.qrc new file mode 100644 index 0000000..10efc6d --- /dev/null +++ b/tools/assistant/lib/helpsystem.qrc @@ -0,0 +1,8 @@ +<RCC> + <qresource prefix="/trolltech/assistant" > + <file>images/1leftarrow.png</file> + <file>images/1rightarrow.png</file> + <file>images/3leftarrow.png</file> + <file>images/3rightarrow.png</file> + </qresource> +</RCC> diff --git a/tools/assistant/lib/images/1leftarrow.png b/tools/assistant/lib/images/1leftarrow.png Binary files differnew file mode 100644 index 0000000..bd1a5a2 --- /dev/null +++ b/tools/assistant/lib/images/1leftarrow.png diff --git a/tools/assistant/lib/images/1rightarrow.png b/tools/assistant/lib/images/1rightarrow.png Binary files differnew file mode 100644 index 0000000..0c0c44a --- /dev/null +++ b/tools/assistant/lib/images/1rightarrow.png diff --git a/tools/assistant/lib/images/3leftarrow.png b/tools/assistant/lib/images/3leftarrow.png Binary files differnew file mode 100644 index 0000000..8d38b0f --- /dev/null +++ b/tools/assistant/lib/images/3leftarrow.png diff --git a/tools/assistant/lib/images/3rightarrow.png b/tools/assistant/lib/images/3rightarrow.png Binary files differnew file mode 100644 index 0000000..c2faf50 --- /dev/null +++ b/tools/assistant/lib/images/3rightarrow.png diff --git a/tools/assistant/lib/lib.pro b/tools/assistant/lib/lib.pro new file mode 100644 index 0000000..bd9ed53 --- /dev/null +++ b/tools/assistant/lib/lib.pro @@ -0,0 +1,65 @@ +QT += sql xml network +TEMPLATE = lib +TARGET = QtHelp +DEFINES += QHELP_LIB QT_CLUCENE_SUPPORT +CONFIG += qt warn_on + +include(../../../src/qbase.pri) + +QMAKE_TARGET_PRODUCT = Help +QMAKE_TARGET_DESCRIPTION = Help application framework. +DEFINES -= QT_ASCII_CAST_WARNINGS + +qclucene = QtCLucene$${QT_LIBINFIX} +if(!debug_and_release|build_pass):CONFIG(debug, debug|release) { + mac:qclucene = $${qclucene}_debug + win32:qclucene = $${qclucene}d +} +linux-lsb-g++:LIBS += --lsb-shared-libs=$$qclucene +unix:QMAKE_PKGCONFIG_REQUIRES += QtNetwork QtSql QtXml +LIBS += -l$$qclucene +unix:QMAKE_PKGCONFIG_REQUIRES += QtNetwork QtSql QtXml + +RESOURCES += helpsystem.qrc + +SOURCES += qhelpenginecore.cpp \ + qhelpengine.cpp \ + qhelpdbreader.cpp \ + qhelpcontentwidget.cpp \ + qhelpindexwidget.cpp \ + qhelpgenerator.cpp \ + qhelpdatainterface.cpp \ + qhelpprojectdata.cpp \ + qhelpcollectionhandler.cpp \ + qhelpsearchengine.cpp \ + qhelpsearchquerywidget.cpp \ + qhelpsearchresultwidget.cpp \ + qhelpsearchindex_default.cpp \ + qhelpsearchindexwriter_default.cpp \ + qhelpsearchindexreader_default.cpp + +# access to clucene +SOURCES += qhelpsearchindexwriter_clucene.cpp \ + qhelpsearchindexreader_clucene.cpp + +HEADERS += qhelpenginecore.h \ + qhelpengine.h \ + qhelpengine_p.h \ + qhelp_global.h \ + qhelpdbreader_p.h \ + qhelpcontentwidget.h \ + qhelpindexwidget.h \ + qhelpgenerator_p.h \ + qhelpdatainterface_p.h \ + qhelpprojectdata_p.h \ + qhelpcollectionhandler_p.h \ + qhelpsearchengine.h \ + qhelpsearchquerywidget.h \ + qhelpsearchresultwidget.h \ + qhelpsearchindex_default_p.h \ + qhelpsearchindexwriter_default_p.h \ + qhelpsearchindexreader_default_p.h + +# access to clucene +HEADERS += qhelpsearchindexwriter_clucene_p.h \ + qhelpsearchindexreader_clucene_p.h diff --git a/tools/assistant/lib/qhelp_global.h b/tools/assistant/lib/qhelp_global.h new file mode 100644 index 0000000..5f09a08 --- /dev/null +++ b/tools/assistant/lib/qhelp_global.h @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELP_GLOBAL_H +#define QHELP_GLOBAL_H + +#include <QtCore/qglobal.h> +#include <QtCore/QString> +#include <QtCore/QObject> +#include <QtCore/QRegExp> +#include <QtCore/QMutexLocker> +#include <QtGui/QTextDocument> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Help) + +#if !defined(QT_SHARED) && !defined(QT_DLL) +# define QHELP_EXPORT +#elif defined(QHELP_LIB) +# define QHELP_EXPORT Q_DECL_EXPORT +#else +# define QHELP_EXPORT Q_DECL_IMPORT +#endif + +class QHelpGlobal { +public: + static QString uniquifyConnectionName(const QString &name, void *pointer) + { + static int counter = 0; + static QMutex mutex; + + QMutexLocker locker(&mutex); + if (++counter > 1000) + counter = 0; + + return QString::fromLatin1("%1-%2-%3") + .arg(name).arg(long(pointer)).arg(counter); + }; + + static QString documentTitle(const QString &content) + { + QString title = QObject::tr("Untitled"); + if (!content.isEmpty()) { + int start = content.indexOf(QLatin1String("<title>"), 0, Qt::CaseInsensitive) + 7; + int end = content.indexOf(QLatin1String("</title>"), 0, Qt::CaseInsensitive); + if ((end - start) > 0) { + title = content.mid(start, end - start); + if (Qt::mightBeRichText(title) || title.contains(QLatin1Char('&'))) { + QTextDocument doc; + doc.setHtml(title); + title = doc.toPlainText(); + } + } + } + return title; + }; + + static QString charsetFromData(const QByteArray &data) + { + QString content = QString::fromUtf8(data.constData(), data.size()); + int start = + content.indexOf(QLatin1String("<meta"), 0, Qt::CaseInsensitive); + if (start > 0) { + int end; + QRegExp r(QLatin1String("charset=([^\"\\s]+)")); + while (start != -1) { + end = content.indexOf(QLatin1Char('>'), start) + 1; + const QString &meta = content.mid(start, end - start).toLower(); + if (r.indexIn(meta) != -1) + return r.cap(1); + start = content.indexOf(QLatin1String("<meta"), end, + Qt::CaseInsensitive); + } + } + return QLatin1String("utf-8"); + } +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QHELP_GLOBAL_H diff --git a/tools/assistant/lib/qhelpcollectionhandler.cpp b/tools/assistant/lib/qhelpcollectionhandler.cpp new file mode 100644 index 0000000..2356591 --- /dev/null +++ b/tools/assistant/lib/qhelpcollectionhandler.cpp @@ -0,0 +1,595 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpcollectionhandler_p.h" +#include "qhelp_global.h" +#include "qhelpdbreader_p.h" + +#include <QtCore/QFile> +#include <QtCore/QDir> +#include <QtCore/QFileInfo> +#include <QtCore/QDebug> + +#include <QtSql/QSqlError> +#include <QtSql/QSqlDriver> + +QT_BEGIN_NAMESPACE + +QHelpCollectionHandler::QHelpCollectionHandler(const QString &collectionFile, QObject *parent) + : QObject(parent) + , m_dbOpened(false) + , m_collectionFile(collectionFile) + , m_connectionName(QString()) +{ + QFileInfo fi(m_collectionFile); + if (!fi.isAbsolute()) + m_collectionFile = fi.absoluteFilePath(); + m_query.clear(); +} + +QHelpCollectionHandler::~QHelpCollectionHandler() +{ + m_query.clear(); + if (m_dbOpened) + QSqlDatabase::removeDatabase(m_connectionName); +} + +bool QHelpCollectionHandler::isDBOpened() +{ + if (m_dbOpened) + return true; + emit error(tr("The collection file is not set up yet!")); + return false; +} + +QString QHelpCollectionHandler::collectionFile() const +{ + return m_collectionFile; +} + +bool QHelpCollectionHandler::openCollectionFile() +{ + if (m_dbOpened) + return m_dbOpened; + + m_connectionName = QHelpGlobal::uniquifyConnectionName( + QLatin1String("QHelpCollectionHandler"), this); + bool openingOk = true; + { + QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), + m_connectionName); + if (db.driver() + && db.driver()->lastError().type() == QSqlError::ConnectionError) { + emit error(tr("Cannot load sqlite database driver!")); + return false; + } + + db.setDatabaseName(collectionFile()); + openingOk = db.open(); + if (openingOk) + m_query = QSqlQuery(db); + } + if (!openingOk) { + QSqlDatabase::removeDatabase(m_connectionName); + emit error(tr("Cannot open collection file: %1").arg(collectionFile())); + return false; + } + + m_query.exec(QLatin1String("SELECT COUNT(*) FROM sqlite_master WHERE TYPE=\'table\'" + "AND Name=\'NamespaceTable\'")); + m_query.next(); + if (m_query.value(0).toInt() < 1) { + if (!createTables(&m_query)) { + emit error(tr("Cannot create tables in file %1!").arg(collectionFile())); + return false; + } + } + + m_dbOpened = true; + return m_dbOpened; +} + +bool QHelpCollectionHandler::copyCollectionFile(const QString &fileName) +{ + if (!m_dbOpened) + return false; + + QFileInfo fi(fileName); + if (fi.exists()) { + emit error(tr("The specified collection file already exists!")); + return false; + } + + if (!fi.absoluteDir().exists() && !QDir().mkpath(fi.absolutePath())) { + emit error(tr("Cannot create directory: %1").arg(fi.absolutePath())); + return false; + } + + QString colFile = fi.absoluteFilePath(); + QString connectionName = QHelpGlobal::uniquifyConnectionName( + QLatin1String("QHelpCollectionHandlerCopy"), this); + QSqlQuery *copyQuery = 0; + bool openingOk = true; + { + QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), connectionName); + db.setDatabaseName(colFile); + openingOk = db.open(); + if (openingOk) + copyQuery = new QSqlQuery(db); + } + + if (!openingOk) { + emit error(tr("Cannot open collection file: %1").arg(colFile)); + return false; + } + + if (!createTables(copyQuery)) { + emit error(tr("Cannot copy collection file: %1").arg(colFile)); + return false; + } + + QString oldBaseDir = QFileInfo(collectionFile()).absolutePath(); + QString oldFilePath; + QFileInfo newColFi(colFile); + m_query.exec(QLatin1String("SELECT Name, FilePath FROM NamespaceTable")); + while (m_query.next()) { + copyQuery->prepare(QLatin1String("INSERT INTO NamespaceTable VALUES(NULL, ?, ?)")); + copyQuery->bindValue(0, m_query.value(0).toString()); + oldFilePath = m_query.value(1).toString(); + if (!QDir::isAbsolutePath(oldFilePath)) + oldFilePath = oldBaseDir + QDir::separator() + oldFilePath; + copyQuery->bindValue(1, newColFi.absoluteDir().relativeFilePath(oldFilePath)); + copyQuery->exec(); + } + + m_query.exec(QLatin1String("SELECT NamespaceId, Name FROM FolderTable")); + while (m_query.next()) { + copyQuery->prepare(QLatin1String("INSERT INTO FolderTable VALUES(NULL, ?, ?)")); + copyQuery->bindValue(0, m_query.value(0).toString()); + copyQuery->bindValue(1, m_query.value(1).toString()); + copyQuery->exec(); + } + + m_query.exec(QLatin1String("SELECT Name FROM FilterAttributeTable")); + while (m_query.next()) { + copyQuery->prepare(QLatin1String("INSERT INTO FilterAttributeTable VALUES(NULL, ?)")); + copyQuery->bindValue(0, m_query.value(0).toString()); + copyQuery->exec(); + } + + m_query.exec(QLatin1String("SELECT Name FROM FilterNameTable")); + while (m_query.next()) { + copyQuery->prepare(QLatin1String("INSERT INTO FilterNameTable VALUES(NULL, ?)")); + copyQuery->bindValue(0, m_query.value(0).toString()); + copyQuery->exec(); + } + + m_query.exec(QLatin1String("SELECT NameId, FilterAttributeId FROM FilterTable")); + while (m_query.next()) { + copyQuery->prepare(QLatin1String("INSERT INTO FilterTable VALUES(?, ?)")); + copyQuery->bindValue(0, m_query.value(0).toInt()); + copyQuery->bindValue(1, m_query.value(1).toInt()); + copyQuery->exec(); + } + + m_query.exec(QLatin1String("SELECT Key, Value FROM SettingsTable")); + while (m_query.next()) { + if (m_query.value(0).toString() == QLatin1String("CluceneSearchNamespaces")) + continue; + copyQuery->prepare(QLatin1String("INSERT INTO SettingsTable VALUES(?, ?)")); + copyQuery->bindValue(0, m_query.value(0).toString()); + copyQuery->bindValue(1, m_query.value(1)); + copyQuery->exec(); + } + + copyQuery->clear(); + delete copyQuery; + QSqlDatabase::removeDatabase(connectionName); + return true; +} + +bool QHelpCollectionHandler::createTables(QSqlQuery *query) +{ + QStringList tables; + tables << QLatin1String("CREATE TABLE NamespaceTable (" + "Id INTEGER PRIMARY KEY, " + "Name TEXT, " + "FilePath TEXT )") + << QLatin1String("CREATE TABLE FolderTable (" + "Id INTEGER PRIMARY KEY, " + "NamespaceId INTEGER, " + "Name TEXT )") + << QLatin1String("CREATE TABLE FilterAttributeTable (" + "Id INTEGER PRIMARY KEY, " + "Name TEXT )") + << QLatin1String("CREATE TABLE FilterNameTable (" + "Id INTEGER PRIMARY KEY, " + "Name TEXT )") + << QLatin1String("CREATE TABLE FilterTable (" + "NameId INTEGER, " + "FilterAttributeId INTEGER )") + << QLatin1String("CREATE TABLE SettingsTable (" + "Key TEXT PRIMARY KEY, " + "Value BLOB )"); + + foreach (QString q, tables) { + if (!query->exec(q)) + return false; + } + return true; +} + +QStringList QHelpCollectionHandler::customFilters() const +{ + QStringList list; + if (m_dbOpened) { + m_query.exec(QLatin1String("SELECT Name FROM FilterNameTable")); + while (m_query.next()) + list.append(m_query.value(0).toString()); + } + return list; +} + +bool QHelpCollectionHandler::removeCustomFilter(const QString &filterName) +{ + if (!isDBOpened() || filterName.isEmpty()) + return false; + + int filterNameId = -1; + m_query.prepare(QLatin1String("SELECT Id FROM FilterNameTable WHERE Name=?")); + m_query.bindValue(0, filterName); + m_query.exec(); + if (m_query.next()) + filterNameId = m_query.value(0).toInt(); + + if (filterNameId < 0) { + emit error(tr("Unknown filter!")); + return false; + } + + m_query.prepare(QLatin1String("DELETE FROM FilterTable WHERE NameId=?")); + m_query.bindValue(0, filterNameId); + m_query.exec(); + + m_query.prepare(QLatin1String("DELETE FROM FilterNameTable WHERE Id=?")); + m_query.bindValue(0, filterNameId); + m_query.exec(); + + return true; +} + +bool QHelpCollectionHandler::addCustomFilter(const QString &filterName, + const QStringList &attributes) +{ + if (!isDBOpened() || filterName.isEmpty()) + return false; + + int nameId = -1; + m_query.prepare(QLatin1String("SELECT Id FROM FilterNameTable WHERE Name=?")); + m_query.bindValue(0, filterName); + m_query.exec(); + while (m_query.next()) { + nameId = m_query.value(0).toInt(); + break; + } + + m_query.exec(QLatin1String("SELECT Id, Name FROM FilterAttributeTable")); + QStringList idsToInsert = attributes; + QMap<QString, int> attributeMap; + while (m_query.next()) { + attributeMap.insert(m_query.value(1).toString(), + m_query.value(0).toInt()); + if (idsToInsert.contains(m_query.value(1).toString())) + idsToInsert.removeAll(m_query.value(1).toString()); + } + + foreach (QString id, idsToInsert) { + m_query.prepare(QLatin1String("INSERT INTO FilterAttributeTable VALUES(NULL, ?)")); + m_query.bindValue(0, id); + m_query.exec(); + attributeMap.insert(id, m_query.lastInsertId().toInt()); + } + + if (nameId < 0) { + m_query.prepare(QLatin1String("INSERT INTO FilterNameTable VALUES(NULL, ?)")); + m_query.bindValue(0, filterName); + if (m_query.exec()) + nameId = m_query.lastInsertId().toInt(); + } + + if (nameId < 0) { + emit error(tr("Cannot register filter %1!").arg(filterName)); + return false; + } + + m_query.prepare(QLatin1String("DELETE FROM FilterTable WHERE NameId=?")); + m_query.bindValue(0, nameId); + m_query.exec(); + + foreach (QString att, attributes) { + m_query.prepare(QLatin1String("INSERT INTO FilterTable VALUES(?, ?)")); + m_query.bindValue(0, nameId); + m_query.bindValue(1, attributeMap[att]); + if (!m_query.exec()) + return false; + } + return true; +} + +QHelpCollectionHandler::DocInfoList QHelpCollectionHandler::registeredDocumentations() const +{ + DocInfoList list; + if (m_dbOpened) { + m_query.exec(QLatin1String("SELECT a.Name, a.FilePath, b.Name " + "FROM NamespaceTable a, FolderTable b WHERE a.Id=b.NamespaceId")); + + while (m_query.next()) { + DocInfo info; + info.fileName = m_query.value(1).toString(); + info.folderName = m_query.value(2).toString(); + info.namespaceName = m_query.value(0).toString(); + list.append(info); + } + } + return list; +} + +bool QHelpCollectionHandler::registerDocumentation(const QString &fileName) +{ + if (!isDBOpened()) + return false; + + QHelpDBReader reader(fileName, QHelpGlobal::uniquifyConnectionName( + QLatin1String("QHelpCollectionHandler"), this), 0); + if (!reader.init()) { + emit error(tr("Cannot open documentation file %1!").arg(fileName)); + return false; + } + + QString ns = reader.namespaceName(); + if (ns.isEmpty()) { + emit error(tr("Invalid documentation file!")); + return false; + } + + int nsId = registerNamespace(ns, fileName); + if (nsId < 1) + return false; + + if (!registerVirtualFolder(reader.virtualFolder(), nsId)) + return false; + + addFilterAttributes(reader.filterAttributes()); + foreach (QString filterName, reader.customFilters()) + addCustomFilter(filterName, reader.filterAttributes(filterName)); + + optimizeDatabase(fileName); + + return true; +} + +bool QHelpCollectionHandler::unregisterDocumentation(const QString &namespaceName) +{ + if (!isDBOpened()) + return false; + + m_query.prepare(QLatin1String("SELECT Id FROM NamespaceTable WHERE Name=?")); + m_query.bindValue(0, namespaceName); + m_query.exec(); + + int nsId = -1; + if (m_query.next()) + nsId = m_query.value(0).toInt(); + + if (nsId < 0) { + emit error(tr("The namespace %1 was not registered!").arg(namespaceName)); + return false; + } + + m_query.prepare(QLatin1String("DELETE FROM NamespaceTable WHERE Id=?")); + m_query.bindValue(0, nsId); + m_query.exec(); + + m_query.prepare(QLatin1String("DELETE FROM FolderTable WHERE NamespaceId=?")); + m_query.bindValue(0, nsId); + return m_query.exec(); +} + +bool QHelpCollectionHandler::removeCustomValue(const QString &key) +{ + if (!isDBOpened()) + return false; + + m_query.prepare(QLatin1String("DELETE FROM SettingsTable WHERE Key=?")); + m_query.bindValue(0, key); + return m_query.exec(); +} + +QVariant QHelpCollectionHandler::customValue(const QString &key, + const QVariant &defaultValue) const +{ + QVariant value = defaultValue; + if (m_dbOpened) { + m_query.prepare(QLatin1String("SELECT COUNT(Key) FROM SettingsTable WHERE Key=?")); + m_query.bindValue(0, key); + if (!m_query.exec() || !m_query.next() || !m_query.value(0).toInt()) { + m_query.clear(); + return defaultValue; + } + + m_query.clear(); + m_query.prepare(QLatin1String("SELECT Value FROM SettingsTable WHERE Key=?")); + m_query.bindValue(0, key); + if (m_query.exec() && m_query.next()) + value = m_query.value(0); + m_query.clear(); + } + return value; +} + +bool QHelpCollectionHandler::setCustomValue(const QString &key, + const QVariant &value) +{ + if (!isDBOpened()) + return false; + + m_query.prepare(QLatin1String("SELECT Value FROM SettingsTable WHERE Key=?")); + m_query.bindValue(0, key); + m_query.exec(); + if (m_query.next()) { + m_query.prepare(QLatin1String("UPDATE SettingsTable SET Value=? where Key=?")); + m_query.bindValue(0, value); + m_query.bindValue(1, key); + } + else { + m_query.prepare(QLatin1String("INSERT INTO SettingsTable VALUES(?, ?)")); + m_query.bindValue(0, key); + m_query.bindValue(1, value); + } + return m_query.exec(); +} + +bool QHelpCollectionHandler::addFilterAttributes(const QStringList &attributes) +{ + if (!isDBOpened()) + return false; + + m_query.exec(QLatin1String("SELECT Name FROM FilterAttributeTable")); + QSet<QString> atts; + while (m_query.next()) + atts.insert(m_query.value(0).toString()); + + foreach (QString s, attributes) { + if (!atts.contains(s)) { + m_query.prepare(QLatin1String("INSERT INTO FilterAttributeTable VALUES(NULL, ?)")); + m_query.bindValue(0, s); + m_query.exec(); + } + } + return true; +} + +QStringList QHelpCollectionHandler::filterAttributes() const +{ + QStringList list; + if (m_dbOpened) { + m_query.exec(QLatin1String("SELECT Name FROM FilterAttributeTable")); + while (m_query.next()) + list.append(m_query.value(0).toString()); + } + return list; +} + +QStringList QHelpCollectionHandler::filterAttributes(const QString &filterName) const +{ + QStringList list; + if (m_dbOpened) { + m_query.prepare(QLatin1String("SELECT a.Name FROM FilterAttributeTable a, " + "FilterTable b, FilterNameTable c WHERE a.Id=b.FilterAttributeId " + "AND b.NameId=c.Id AND c.Name=?")); + m_query.bindValue(0, filterName); + m_query.exec(); + while (m_query.next()) + list.append(m_query.value(0).toString()); + } + return list; +} + +int QHelpCollectionHandler::registerNamespace(const QString &nspace, const QString &fileName) +{ + m_query.prepare(QLatin1String("SELECT COUNT(Id) FROM NamespaceTable WHERE Name=?")); + m_query.bindValue(0, nspace); + m_query.exec(); + while (m_query.next()) { + if (m_query.value(0).toInt() > 0) { + emit error(tr("Namespace %1 already exists!").arg(nspace)); + return -1; + } + } + + QFileInfo fi(m_collectionFile); + m_query.prepare(QLatin1String("INSERT INTO NamespaceTable VALUES(NULL, ?, ?)")); + m_query.bindValue(0, nspace); + m_query.bindValue(1, fi.absoluteDir().relativeFilePath(fileName)); + int namespaceId = -1; + if (m_query.exec()) + namespaceId = m_query.lastInsertId().toInt(); + if (namespaceId < 1) { + emit error(tr("Cannot register namespace!")); + return -1; + } + return namespaceId; +} + +bool QHelpCollectionHandler::registerVirtualFolder(const QString &folderName, int namespaceId) +{ + m_query.prepare(QLatin1String("INSERT INTO FolderTable VALUES(NULL, ?, ?)")); + m_query.bindValue(0, namespaceId); + m_query.bindValue(1, folderName); + return m_query.exec(); +} + +void QHelpCollectionHandler::optimizeDatabase(const QString &fileName) +{ + if (!QFile::exists(fileName)) + return; + + { // according to removeDatabase() documentation + QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), QLatin1String("optimize")); + db.setDatabaseName(fileName); + if (!db.open()) { + QSqlDatabase::removeDatabase(QLatin1String("optimize")); + emit error(tr("Cannot open database to optimize!")); + return; + } + + QSqlQuery query(db); + db.exec(QLatin1String("CREATE INDEX IF NOT EXISTS NameIndex ON IndexTable(Name)")); + db.exec(QLatin1String("CREATE INDEX IF NOT EXISTS FileNameIndex ON FileNameTable(Name)")); + db.exec(QLatin1String("CREATE INDEX IF NOT EXISTS FileIdIndex ON FileNameTable(FileId)")); + + db.close(); + } + + QSqlDatabase::removeDatabase(QLatin1String("optimize")); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpcollectionhandler_p.h b/tools/assistant/lib/qhelpcollectionhandler_p.h new file mode 100644 index 0000000..2520694 --- /dev/null +++ b/tools/assistant/lib/qhelpcollectionhandler_p.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPCOLLECTIONHANDLER_H +#define QHELPCOLLECTIONHANDLER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QList> +#include <QtCore/QString> +#include <QtCore/QObject> +#include <QtCore/QVariant> +#include <QtCore/QStringList> + +#include <QtSql/QSqlQuery> + +QT_BEGIN_NAMESPACE + +class QHelpCollectionHandler : public QObject +{ + Q_OBJECT + +public: + struct DocInfo + { + QString fileName; + QString folderName; + QString namespaceName; + }; + typedef QList<DocInfo> DocInfoList; + + QHelpCollectionHandler(const QString &collectionFile, QObject *parent = 0); + ~QHelpCollectionHandler(); + + QString collectionFile() const; + + bool openCollectionFile(); + bool copyCollectionFile(const QString &fileName); + + QStringList customFilters() const; + bool removeCustomFilter(const QString &filterName); + bool addCustomFilter(const QString &filterName, + const QStringList &attributes); + + DocInfoList registeredDocumentations() const; + bool registerDocumentation(const QString &fileName); + bool unregisterDocumentation(const QString &namespaceName); + + bool removeCustomValue(const QString &key); + QVariant customValue(const QString &key, const QVariant &defaultValue) const; + bool setCustomValue(const QString &key, const QVariant &value); + + bool addFilterAttributes(const QStringList &attributes); + QStringList filterAttributes() const; + QStringList filterAttributes(const QString &filterName) const; + + int registerNamespace(const QString &nspace, const QString &fileName); + bool registerVirtualFolder(const QString &folderName, int namespaceId); + void optimizeDatabase(const QString &fileName); + +signals: + void error(const QString &msg); + +private: + bool isDBOpened(); + bool createTables(QSqlQuery *query); + + bool m_dbOpened; + QString m_collectionFile; + QString m_connectionName; + mutable QSqlQuery m_query; +}; + +QT_END_NAMESPACE + +#endif //QHELPCOLLECTIONHANDLER_H diff --git a/tools/assistant/lib/qhelpcontentwidget.cpp b/tools/assistant/lib/qhelpcontentwidget.cpp new file mode 100644 index 0000000..c70aef3 --- /dev/null +++ b/tools/assistant/lib/qhelpcontentwidget.cpp @@ -0,0 +1,585 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpcontentwidget.h" +#include "qhelpenginecore.h" +#include "qhelpengine_p.h" +#include "qhelpdbreader_p.h" + +#include <QtCore/QDir> +#include <QtCore/QStack> +#include <QtCore/QThread> +#include <QtCore/QMutex> +#include <QtGui/QHeaderView> + +QT_BEGIN_NAMESPACE + +class QHelpContentItemPrivate +{ +public: + QHelpContentItemPrivate(const QString &t, const QString &l, + QHelpDBReader *r, QHelpContentItem *p) + { + parent = p; + title = t; + link = l; + helpDBReader = r; + } + + QList<QHelpContentItem*> childItems; + QHelpContentItem *parent; + QString title; + QString link; + QHelpDBReader *helpDBReader; +}; + +class QHelpContentProvider : public QThread +{ +public: + QHelpContentProvider(QHelpEnginePrivate *helpEngine); + ~QHelpContentProvider(); + void collectContents(const QString &customFilterName); + void stopCollecting(); + QHelpContentItem *rootItem(); + int nextChildCount() const; + +private: + void run(); + + QHelpEnginePrivate *m_helpEngine; + QHelpContentItem *m_rootItem; + QStringList m_filterAttributes; + QQueue<QHelpContentItem*> m_rootItems; + QMutex m_mutex; + bool m_abort; +}; + +class QHelpContentModelPrivate +{ +public: + QHelpContentItem *rootItem; + QHelpContentProvider *qhelpContentProvider; +}; + + + +/*! + \class QHelpContentItem + \inmodule QtHelp + \brief The QHelpContentItem class provides an item for use with QHelpContentModel. + \since 4.4 +*/ + +QHelpContentItem::QHelpContentItem(const QString &name, const QString &link, + QHelpDBReader *reader, QHelpContentItem *parent) +{ + d = new QHelpContentItemPrivate(name, link, reader, parent); +} + +/*! + Destroys the help content item. +*/ +QHelpContentItem::~QHelpContentItem() +{ + qDeleteAll(d->childItems); + delete d; +} + +void QHelpContentItem::appendChild(QHelpContentItem *item) +{ + d->childItems.append(item); +} + +/*! + Returns the child of the content item in the give \a row. + + \sa parent() +*/ +QHelpContentItem *QHelpContentItem::child(int row) const +{ + if (row >= childCount()) + return 0; + return d->childItems.value(row); +} + +/*! + Returns the number of child items. +*/ +int QHelpContentItem::childCount() const +{ + return d->childItems.count(); +} + +/*! + Returns the row of this item from its parents view. +*/ +int QHelpContentItem::row() const +{ + if (d->parent) + return d->parent->d->childItems.indexOf(const_cast<QHelpContentItem*>(this)); + return 0; +} + +/*! + Returns the title of the content item. +*/ +QString QHelpContentItem::title() const +{ + return d->title; +} + +/*! + Returns the URL of this content item. +*/ +QUrl QHelpContentItem::url() const +{ + return d->helpDBReader->urlOfPath(d->link); +} + +/*! + Returns the parent content item. +*/ +QHelpContentItem *QHelpContentItem::parent() const +{ + return d->parent; +} + +/*! + Returns the position of a given \a child. +*/ +int QHelpContentItem::childPosition(QHelpContentItem *child) const +{ + return d->childItems.indexOf(child); +} + + + +QHelpContentProvider::QHelpContentProvider(QHelpEnginePrivate *helpEngine) + : QThread(helpEngine) +{ + m_helpEngine = helpEngine; + m_rootItem = 0; + m_abort = false; +} + +QHelpContentProvider::~QHelpContentProvider() +{ + stopCollecting(); +} + +void QHelpContentProvider::collectContents(const QString &customFilterName) +{ + m_mutex.lock(); + m_filterAttributes = m_helpEngine->q->filterAttributes(customFilterName); + m_mutex.unlock(); + if (!isRunning()) { + start(LowPriority); + } else { + stopCollecting(); + start(LowPriority); + } +} + +void QHelpContentProvider::stopCollecting() +{ + if (!isRunning()) + return; + m_mutex.lock(); + m_abort = true; + m_mutex.unlock(); + wait(); +} + +QHelpContentItem *QHelpContentProvider::rootItem() +{ + QMutexLocker locker(&m_mutex); + return m_rootItems.dequeue(); +} + +int QHelpContentProvider::nextChildCount() const +{ + return m_rootItems.head()->childCount(); +} + +void QHelpContentProvider::run() +{ + QString title; + QString link; + int depth = 0; + QHelpContentItem *item = 0; + + m_mutex.lock(); + m_rootItem = new QHelpContentItem(QString(), QString(), 0); + m_rootItems.enqueue(m_rootItem); + QStringList atts = m_filterAttributes; + const QStringList fileNames = m_helpEngine->orderedFileNameList; + m_mutex.unlock(); + + foreach (QString dbFileName, fileNames) { + m_mutex.lock(); + if (m_abort) { + m_abort = false; + m_mutex.unlock(); + break; + } + m_mutex.unlock(); + QHelpDBReader reader(dbFileName, + QHelpGlobal::uniquifyConnectionName(dbFileName + + QLatin1String("FromQHelpContentProvider"), + QThread::currentThread()), 0); + if (!reader.init()) + continue; + foreach (const QByteArray& ba, reader.contentsForFilter(atts)) { + if (ba.size() < 1) + continue; + + int _depth = 0; + bool _root = false; + QStack<QHelpContentItem*> stack; + + QDataStream s(ba); + for (;;) { + s >> depth; + s >> link; + s >> title; + if (title.isEmpty()) + break; +CHECK_DEPTH: + if (depth == 0) { + m_mutex.lock(); + item = new QHelpContentItem(title, link, + m_helpEngine->fileNameReaderMap.value(dbFileName), m_rootItem); + m_rootItem->appendChild(item); + m_mutex.unlock(); + stack.push(item); + _depth = 1; + _root = true; + } else { + if (depth > _depth && _root) { + _depth = depth; + stack.push(item); + } + if (depth == _depth) { + item = new QHelpContentItem(title, link, + m_helpEngine->fileNameReaderMap.value(dbFileName), stack.top()); + stack.top()->appendChild(item); + } else if (depth < _depth) { + stack.pop(); + --_depth; + goto CHECK_DEPTH; + } + } + } + } + } + m_mutex.lock(); + m_abort = false; + m_mutex.unlock(); +} + + + +/*! + \class QHelpContentModel + \inmodule QtHelp + \brief The QHelpContentModel class provides a model that supplies content to views. + \since 4.4 +*/ + +/*! + \fn void QHelpContentModel::contentsCreationStarted() + + This signal is emitted when the creation of the contents has + started. The current contents are invalid from this point on + until the signal contentsCreated() is emitted. + + \sa isCreatingContents() +*/ + +/*! + \fn void QHelpContentModel::contentsCreated() + + This signal is emitted when the contents have been created. +*/ + +QHelpContentModel::QHelpContentModel(QHelpEnginePrivate *helpEngine) + : QAbstractItemModel(helpEngine) +{ + d = new QHelpContentModelPrivate(); + d->rootItem = 0; + d->qhelpContentProvider = new QHelpContentProvider(helpEngine); + + connect(d->qhelpContentProvider, SIGNAL(finished()), + this, SLOT(insertContents()), Qt::QueuedConnection); + connect(helpEngine->q, SIGNAL(setupStarted()), this, SLOT(invalidateContents())); +} + +/*! + Destroys the help content model. +*/ +QHelpContentModel::~QHelpContentModel() +{ + delete d->rootItem; + delete d; +} + +void QHelpContentModel::invalidateContents(bool onShutDown) +{ + if (onShutDown) + disconnect(this, SLOT(insertContents())); + d->qhelpContentProvider->stopCollecting(); + if (d->rootItem) { + delete d->rootItem; + d->rootItem = 0; + } + reset(); +} + +/*! + Creates new contents by querying the help system + for contents specified for the \a customFilterName. +*/ +void QHelpContentModel::createContents(const QString &customFilterName) +{ + d->qhelpContentProvider->collectContents(customFilterName); + emit contentsCreationStarted(); +} + +void QHelpContentModel::insertContents() +{ + int count; + if (d->rootItem) { + count = d->rootItem->childCount() - 1; + beginRemoveRows(QModelIndex(), 0, count > 0 ? count : 0); + delete d->rootItem; + d->rootItem = 0; + endRemoveRows(); + } + + count = d->qhelpContentProvider->nextChildCount() - 1; + beginInsertRows(QModelIndex(), 0, count > 0 ? count : 0); + d->rootItem = d->qhelpContentProvider->rootItem(); + endInsertRows(); + reset(); + emit contentsCreated(); +} + +/*! + Returns true if the contents are currently rebuilt, otherwise + false. +*/ +bool QHelpContentModel::isCreatingContents() const +{ + return d->qhelpContentProvider->isRunning(); +} + +/*! + Returns the help content item at the model index position + \a index. +*/ +QHelpContentItem *QHelpContentModel::contentItemAt(const QModelIndex &index) const +{ + if (index.isValid()) + return static_cast<QHelpContentItem*>(index.internalPointer()); + else + return d->rootItem; +} + +/*! + Returns the index of the item in the model specified by + the given \a row, \a column and \a parent index. +*/ +QModelIndex QHelpContentModel::index(int row, int column, const QModelIndex &parent) const +{ + if (!d->rootItem) + return QModelIndex(); + + QHelpContentItem *parentItem = contentItemAt(parent); + QHelpContentItem *item = parentItem->child(row); + if (!item) + return QModelIndex(); + return createIndex(row, column, item); +} + +/*! + Returns the parent of the model item with the given + \a index, or QModelIndex() if it has no parent. +*/ +QModelIndex QHelpContentModel::parent(const QModelIndex &index) const +{ + QHelpContentItem *item = contentItemAt(index); + if (!item) + return QModelIndex(); + + QHelpContentItem *parentItem = static_cast<QHelpContentItem*>(item->parent()); + if (!parentItem) + return QModelIndex(); + + QHelpContentItem *grandparentItem = static_cast<QHelpContentItem*>(parentItem->parent()); + if (!grandparentItem) + return QModelIndex(); + + int row = grandparentItem->childPosition(parentItem); + return createIndex(row, index.column(), parentItem); +} + +/*! + Returns the number of rows under the given \a parent. +*/ +int QHelpContentModel::rowCount(const QModelIndex &parent) const +{ + QHelpContentItem *parentItem = contentItemAt(parent); + if (!parentItem) + return 0; + return parentItem->childCount(); +} + +/*! + Returns the number of columns under the given \a parent. Currently returns always 1. +*/ +int QHelpContentModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + + return 1; +} + +/*! + Returns the data stored under the given \a role for + the item referred to by the \a index. +*/ +QVariant QHelpContentModel::data(const QModelIndex &index, int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + QHelpContentItem *item = contentItemAt(index); + if (!item) + return QVariant(); + return item->title(); +} + + + +/*! + \class QHelpContentWidget + \inmodule QtHelp + \brief The QHelpContentWidget class provides a tree view for displaying help content model items. + \since 4.4 +*/ + +/*! + \fn void QHelpContentWidget::linkActivated(const QUrl &link) + + This signal is emitted when a content item is activated and + its associated \a link should be shown. +*/ + +QHelpContentWidget::QHelpContentWidget() + : QTreeView(0) +{ + header()->hide(); + setUniformRowHeights(true); + connect(this, SIGNAL(activated(const QModelIndex&)), + this, SLOT(showLink(const QModelIndex&))); +} + +/*! + Returns the index of the content item with the \a link. + An invalid index is returned if no such an item exists. +*/ +QModelIndex QHelpContentWidget::indexOf(const QUrl &link) +{ + QHelpContentModel *contentModel = + qobject_cast<QHelpContentModel*>(model()); + if (!contentModel || link.scheme() != QLatin1String("qthelp")) + return QModelIndex(); + + m_syncIndex = QModelIndex(); + for (int i=0; i<contentModel->rowCount(); ++i) { + QHelpContentItem *itm = + contentModel->contentItemAt(contentModel->index(i, 0)); + if (itm && itm->url().host() == link.host()) { + QString path = link.path(); + if (path.startsWith(QLatin1Char('/'))) + path = path.mid(1); + if (searchContentItem(contentModel, contentModel->index(i, 0), path)) { + return m_syncIndex; + } + } + } + return QModelIndex(); +} + +bool QHelpContentWidget::searchContentItem(QHelpContentModel *model, + const QModelIndex &parent, const QString &path) +{ + QHelpContentItem *parentItem = model->contentItemAt(parent); + if (!parentItem) + return false; + + if (QDir::cleanPath(parentItem->url().path()) == path) { + m_syncIndex = parent; + return true; + } + + for (int i=0; i<parentItem->childCount(); ++i) { + if (searchContentItem(model, model->index(i, 0, parent), path)) + return true; + } + return false; +} + +void QHelpContentWidget::showLink(const QModelIndex &index) +{ + QHelpContentModel *contentModel = qobject_cast<QHelpContentModel*>(model()); + if (!contentModel) + return; + + QHelpContentItem *item = contentModel->contentItemAt(index); + if (!item) + return; + QUrl url = item->url(); + if (url.isValid()) + emit linkActivated(url); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpcontentwidget.h b/tools/assistant/lib/qhelpcontentwidget.h new file mode 100644 index 0000000..ceab7fe --- /dev/null +++ b/tools/assistant/lib/qhelpcontentwidget.h @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPCONTENTWIDGET_H +#define QHELPCONTENTWIDGET_H + +#include <QtHelp/qhelp_global.h> + +#include <QtCore/QQueue> +#include <QtCore/QString> +#include <QtGui/QTreeView> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Help) + +class QHelpEnginePrivate; +class QHelpDBReader; +class QHelpContentItemPrivate; +class QHelpContentModelPrivate; +class QHelpEngine; +class QHelpContentProvider; + +class QHELP_EXPORT QHelpContentItem +{ +public: + ~QHelpContentItem(); + + QHelpContentItem *child(int row) const; + int childCount() const; + QString title() const; + QUrl url() const; + int row() const; + QHelpContentItem *parent() const; + int childPosition(QHelpContentItem *child) const; + +private: + QHelpContentItem(const QString &name, const QString &link, + QHelpDBReader *reader, QHelpContentItem *parent = 0); + void appendChild(QHelpContentItem *child); + + QHelpContentItemPrivate *d; + friend class QHelpContentProvider; +}; + +class QHELP_EXPORT QHelpContentModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + ~QHelpContentModel(); + + void createContents(const QString &customFilterName); + QHelpContentItem *contentItemAt(const QModelIndex &index) const; + + QVariant data(const QModelIndex &index, int role) const; + QModelIndex index(int row, int column, + const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &index) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + bool isCreatingContents() const; + +Q_SIGNALS: + void contentsCreationStarted(); + void contentsCreated(); + +private Q_SLOTS: + void insertContents(); + void invalidateContents(bool onShutDown = false); + +private: + QHelpContentModel(QHelpEnginePrivate *helpEngine); + QHelpContentModelPrivate *d; + friend class QHelpEnginePrivate; +}; + +class QHELP_EXPORT QHelpContentWidget : public QTreeView +{ + Q_OBJECT + +public: + QModelIndex indexOf(const QUrl &link); + +Q_SIGNALS: + void linkActivated(const QUrl &link); + +private Q_SLOTS: + void showLink(const QModelIndex &index); + +private: + bool searchContentItem(QHelpContentModel *model, + const QModelIndex &parent, const QString &path); + QModelIndex m_syncIndex; + +private: + QHelpContentWidget(); + friend class QHelpEngine; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif + diff --git a/tools/assistant/lib/qhelpdatainterface.cpp b/tools/assistant/lib/qhelpdatainterface.cpp new file mode 100644 index 0000000..001c059 --- /dev/null +++ b/tools/assistant/lib/qhelpdatainterface.cpp @@ -0,0 +1,273 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpdatainterface_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \internal + \class QHelpDataContentItem + \since 4.4 + \brief The QHelpDataContentItem class provides an item which represents + a topic or section of the contents. + + Every item holds several pieces of information, most notably the title + which can later be displayed in a contents overview. The reference is used + to store a relative file link to the corresponding section in the + documentation. +*/ + +/*! + Constructs a new content item with \a parent as parent item. + The constucted item has the title \a title and links to the + location specified by \a reference. +*/ +QHelpDataContentItem::QHelpDataContentItem(QHelpDataContentItem *parent, + const QString &title, const QString &reference) + : m_title(title), m_reference(reference) +{ + if (parent) + parent->m_children.append(this); +} + +/*! + Destructs the item and its children. +*/ +QHelpDataContentItem::~QHelpDataContentItem() +{ + qDeleteAll(m_children); +} + +/*! + Returns the title of the item. +*/ +QString QHelpDataContentItem::title() const +{ + return m_title; +} + +/*! + Returns the file reference of the item. +*/ +QString QHelpDataContentItem::reference() const +{ + return m_reference; +} + +/*! + Returns a list of all its child items. +*/ +QList<QHelpDataContentItem*> QHelpDataContentItem::children() const +{ + return m_children; +} + +bool QHelpDataIndexItem::operator==(const QHelpDataIndexItem & other) const +{ + return (other.name == name) + && (other.reference == reference); +} + + + +/*! + \internal + \class QHelpDataFilterSection + \since 4.4 +*/ + +/*! + Constructs a help data filter section. +*/ +QHelpDataFilterSection::QHelpDataFilterSection() +{ + d = new QHelpDataFilterSectionData(); +} + +/*! + Adds the filter attribute \a filter to the filter attributes of + this section. +*/ +void QHelpDataFilterSection::addFilterAttribute(const QString &filter) +{ + d->filterAttributes.append(filter); +} + +/*! + Returns a list of all filter attributes defined for this section. +*/ +QStringList QHelpDataFilterSection::filterAttributes() const +{ + return d->filterAttributes; +} + +/*! + Adds the index item \a index to the list of indices. +*/ +void QHelpDataFilterSection::addIndex(const QHelpDataIndexItem &index) +{ + d->indices.append(index); +} + +/*! + Sets the filter sections list of indices to \a indices. +*/ +void QHelpDataFilterSection::setIndices(const QList<QHelpDataIndexItem> &indices) +{ + d->indices = indices; +} + +/*! + Returns the list of indices. +*/ +QList<QHelpDataIndexItem> QHelpDataFilterSection::indices() const +{ + return d->indices; +} + +/*! + Adds the top level content item \a content to the filter section. +*/ +void QHelpDataFilterSection::addContent(QHelpDataContentItem *content) +{ + d->contents.append(content); +} + +/*! + Sets the list of top level content items of the filter section to + \a contents. +*/ +void QHelpDataFilterSection::setContents(const QList<QHelpDataContentItem*> &contents) +{ + qDeleteAll(d->contents); + d->contents = contents; +} + +/*! + Returns a list of top level content items. +*/ +QList<QHelpDataContentItem*> QHelpDataFilterSection::contents() const +{ + return d->contents; +} + +/*! + Adds the file \a file to the filter section. +*/ +void QHelpDataFilterSection::addFile(const QString &file) +{ + d->files.append(file); +} + +/*! + Set the list of files to \a files. +*/ +void QHelpDataFilterSection::setFiles(const QStringList &files) +{ + d->files = files; +} + +/*! + Returns the list of files. +*/ +QStringList QHelpDataFilterSection::files() const +{ + return d->files; +} + +/*! + \internal + \class QHelpDataInterface + \since 4.4 +*/ + +/*! + \fn QHelpDataInterface::QHelpDataInterface() + + Constructs a new help data interface. +*/ + +/*! + \fn QHelpDataInterface::~QHelpDataInterface() + + Destroys the help data interface. +*/ + +/*! + \fn QString QHelpDataInterface::namespaceName() const = 0 + + Returns the namespace name of the help data set. +*/ + +/*! + \fn QString QHelpDataInterface::virtualFolder() const = 0 + + Returns the virtual folder of the help data set. +*/ + +/*! + \fn QList<QHelpDataCustomFilter> QHelpDataInterface::customFilters () const = 0 + + Returns a list of custom filters. Defining custom filters is optional. +*/ + +/*! + \fn QList<QHelpDataFilterSection> QHelpDataInterface::filterSections() const = 0 + + Returns a list of filter sections. +*/ + +/*! + \fn QMap<QString, QVariant> QHelpDataInterface::metaData() const = 0 + + Returns a map of meta data. A meta data item can hold almost any data + and is identified by its name. +*/ + +/*! + \fn QString QHelpDataInterface::rootPath() const = 0 + + Returns the root file path of the documentation data. All referenced file + path or links of content items are relative to this path. +*/ + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpdatainterface_p.h b/tools/assistant/lib/qhelpdatainterface_p.h new file mode 100644 index 0000000..2d05cc6 --- /dev/null +++ b/tools/assistant/lib/qhelpdatainterface_p.h @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPDATAINTERFACE_H +#define QHELPDATAINTERFACE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhelp_global.h" + +#include <QtCore/QStringList> +#include <QtCore/QSharedData> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QHELP_EXPORT QHelpDataContentItem +{ +public: + QHelpDataContentItem(QHelpDataContentItem *parent, const QString &title, + const QString &reference); + ~QHelpDataContentItem(); + + QString title() const; + QString reference() const; + QList<QHelpDataContentItem*> children() const; + +private: + QString m_title; + QString m_reference; + QList<QHelpDataContentItem*> m_children; +}; + +struct QHELP_EXPORT QHelpDataIndexItem { + QHelpDataIndexItem() {} + QHelpDataIndexItem(const QString &n, const QString &id, const QString &r) + : name(n), identifier(id), reference(r) {} + + QString name; + QString identifier; + QString reference; + + bool operator==(const QHelpDataIndexItem & other) const; +}; + +class QHelpDataFilterSectionData : public QSharedData +{ +public: + ~QHelpDataFilterSectionData() + { + qDeleteAll(contents); + } + + QStringList filterAttributes; + QList<QHelpDataIndexItem> indices; + QList<QHelpDataContentItem*> contents; + QStringList files; +}; + +class QHELP_EXPORT QHelpDataFilterSection +{ +public: + QHelpDataFilterSection(); + + void addFilterAttribute(const QString &filter); + QStringList filterAttributes() const; + + void addIndex(const QHelpDataIndexItem &index); + void setIndices(const QList<QHelpDataIndexItem> &indices); + QList<QHelpDataIndexItem> indices() const; + + void addContent(QHelpDataContentItem *content); + void setContents(const QList<QHelpDataContentItem*> &contents); + QList<QHelpDataContentItem*> contents() const; + + void addFile(const QString &file); + void setFiles(const QStringList &files); + QStringList files() const; + +private: + QSharedDataPointer<QHelpDataFilterSectionData> d; +}; + +struct QHELP_EXPORT QHelpDataCustomFilter { + QStringList filterAttributes; + QString name; +}; + +class QHELP_EXPORT QHelpDataInterface +{ +public: + QHelpDataInterface() {} + virtual ~QHelpDataInterface() {} + + virtual QString namespaceName() const = 0; + virtual QString virtualFolder() const = 0; + virtual QList<QHelpDataCustomFilter> customFilters() const = 0; + virtual QList<QHelpDataFilterSection> filterSections() const = 0; + virtual QMap<QString, QVariant> metaData() const = 0; + virtual QString rootPath() const = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QHELPDATAINTERFACE_H diff --git a/tools/assistant/lib/qhelpdbreader.cpp b/tools/assistant/lib/qhelpdbreader.cpp new file mode 100644 index 0000000..76994a7 --- /dev/null +++ b/tools/assistant/lib/qhelpdbreader.cpp @@ -0,0 +1,580 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpdbreader_p.h" +#include "qhelp_global.h" + +#include <QtCore/QVariant> +#include <QtCore/QFile> +#include <QtSql/QSqlError> +#include <QtSql/QSqlQuery> + +QT_BEGIN_NAMESPACE + +QHelpDBReader::QHelpDBReader(const QString &dbName) + : QObject(0) +{ + initObject(dbName, + QHelpGlobal::uniquifyConnectionName(QLatin1String("QHelpDBReader"), + this)); +} + +QHelpDBReader::QHelpDBReader(const QString &dbName, const QString &uniqueId, + QObject *parent) + : QObject(parent) +{ + initObject(dbName, uniqueId); +} + +void QHelpDBReader::initObject(const QString &dbName, const QString &uniqueId) +{ + m_dbName = dbName; + m_uniqueId = uniqueId; + m_initDone = false; + m_query = 0; + m_useAttributesCache = false; +} + +QHelpDBReader::~QHelpDBReader() +{ + if (m_initDone) { + delete m_query; + QSqlDatabase::removeDatabase(m_uniqueId); + } +} + +bool QHelpDBReader::init() +{ + if (m_initDone) + return true; + + if (!QFile::exists(m_dbName)) + return false; + + QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), m_uniqueId); + db.setDatabaseName(m_dbName); + if (!db.open()) { + m_error = tr("Cannot open database '%1' '%2': %3").arg(m_dbName, m_uniqueId, db.lastError().text()); + QSqlDatabase::removeDatabase(m_uniqueId); + return false; + } + + m_initDone = true; + m_query = new QSqlQuery(db); + + return true; +} + +QString QHelpDBReader::databaseName() const +{ + return m_dbName; +} + +QString QHelpDBReader::errorMessage() const +{ + return m_error; +} + +QString QHelpDBReader::namespaceName() const +{ + if (!m_namespace.isEmpty()) + return m_namespace; + if (m_query) { + m_query->exec(QLatin1String("SELECT Name FROM NamespaceTable")); + if (m_query->next()) + m_namespace = m_query->value(0).toString(); + } + return m_namespace; +} + +QString QHelpDBReader::virtualFolder() const +{ + if (m_query) { + m_query->exec(QLatin1String("SELECT Name FROM FolderTable WHERE Id=1")); + if (m_query->next()) + return m_query->value(0).toString(); + } + return QString(); +} + +QList<QStringList> QHelpDBReader::filterAttributeSets() const +{ + QList<QStringList> result; + if (m_query) { + m_query->exec(QLatin1String("SELECT a.Id, b.Name FROM FileAttributeSetTable a, " + "FilterAttributeTable b WHERE a.FilterAttributeId=b.Id ORDER BY a.Id")); + int oldId = -1; + while (m_query->next()) { + int id = m_query->value(0).toInt(); + if (id != oldId) { + result.append(QStringList()); + oldId = id; + } + result.last().append(m_query->value(1).toString()); + } + } + return result; +} + +bool QHelpDBReader::fileExists(const QString &virtualFolder, + const QString &filePath, + const QStringList &filterAttributes) const +{ + if (virtualFolder.isEmpty() || filePath.isEmpty() || !m_query) + return false; + +//SELECT COUNT(a.Name) FROM FileNameTable a, FolderTable b, FileFilterTable c, FilterAttributeTable d WHERE a.FolderId=b.Id AND b.Name='qtdoc' AND a.Name='qstring.html' AND a.FileId=c.FileId AND c.FilterAttributeId=d.Id AND d.Name='qtrefdoc' + + QString query; + namespaceName(); + if (filterAttributes.isEmpty()) { + query = QString(QLatin1String("SELECT COUNT(a.Name) FROM FileNameTable a, FolderTable b " + "WHERE a.FolderId=b.Id AND b.Name=\'%1\' AND a.Name=\'%2\'")).arg(quote(virtualFolder)).arg(quote(filePath)); + } else { + query = QString(QLatin1String("SELECT COUNT(a.Name) FROM FileNameTable a, FolderTable b, " + "FileFilterTable c, FilterAttributeTable d WHERE a.FolderId=b.Id " + "AND b.Name=\'%1\' AND a.Name=\'%2\' AND a.FileId=c.FileId AND " + "c.FilterAttributeId=d.Id AND d.Name=\'%3\'")) + .arg(quote(virtualFolder)).arg(quote(filePath)) + .arg(quote(filterAttributes.first())); + for (int i=1; i<filterAttributes.count(); ++i) { + query.append(QString(QLatin1String(" INTERSECT SELECT COUNT(a.Name) FROM FileNameTable a, " + "FolderTable b, FileFilterTable c, FilterAttributeTable d WHERE a.FolderId=b.Id " + "AND b.Name=\'%1\' AND a.Name=\'%2\' AND a.FileId=c.FileId AND " + "c.FilterAttributeId=d.Id AND d.Name=\'%3\'")) + .arg(quote(virtualFolder)).arg(quote(filePath)) + .arg(quote(filterAttributes.at(i)))); + } + } + m_query->exec(query); + if (m_query->next() && m_query->isValid() && m_query->value(0).toInt()) + return true; + return false; +} + +QByteArray QHelpDBReader::fileData(const QString &virtualFolder, + const QString &filePath) const +{ + QByteArray ba; + if (virtualFolder.isEmpty() || filePath.isEmpty() || !m_query) + return ba; + + namespaceName(); + m_query->prepare(QLatin1String("SELECT a.Data FROM FileDataTable a, FileNameTable b, FolderTable c, " + "NamespaceTable d WHERE a.Id=b.FileId AND (b.Name=? OR b.Name=?) AND b.FolderId=c.Id " + "AND c.Name=? AND c.NamespaceId=d.Id AND d.Name=?")); + m_query->bindValue(0, filePath); + m_query->bindValue(1, QLatin1String("./") + filePath); + m_query->bindValue(2, virtualFolder); + m_query->bindValue(3, m_namespace); + m_query->exec(); + if (m_query->next() && m_query->isValid()) + ba = qUncompress(m_query->value(0).toByteArray()); + return ba; +} + +QStringList QHelpDBReader::customFilters() const +{ + QStringList lst; + if (m_query) { + m_query->exec(QLatin1String("SELECT Name FROM FilterNameTable")); + while (m_query->next()) + lst.append(m_query->value(0).toString()); + } + return lst; +} + +QStringList QHelpDBReader::filterAttributes(const QString &filterName) const +{ + QStringList lst; + if (m_query) { + if (filterName.isEmpty()) { + m_query->prepare(QLatin1String("SELECT Name FROM FilterAttributeTable")); + } else { + m_query->prepare(QLatin1String("SELECT a.Name FROM FilterAttributeTable a, " + "FilterTable b, FilterNameTable c WHERE c.Name=? " + "AND c.Id=b.NameId AND b.FilterAttributeId=a.Id")); + m_query->bindValue(0, filterName); + } + m_query->exec(); + while (m_query->next()) + lst.append(m_query->value(0).toString()); + } + return lst; +} + +QStringList QHelpDBReader::indicesForFilter(const QStringList &filterAttributes) const +{ + QStringList indices; + if (!m_query) + return indices; + + //SELECT DISTINCT a.Name FROM IndexTable a, IndexFilterTable b, FilterAttributeTable c WHERE a.Id=b.IndexId AND b.FilterAttributeId=c.Id AND c.Name in ('4.2.3', 'qt') + + QString query; + if (filterAttributes.isEmpty()) { + query = QLatin1String("SELECT DISTINCT Name FROM IndexTable"); + } else { + query = QString(QLatin1String("SELECT DISTINCT a.Name FROM IndexTable a, " + "IndexFilterTable b, FilterAttributeTable c WHERE a.Id=b.IndexId " + "AND b.FilterAttributeId=c.Id AND c.Name='%1'")).arg(quote(filterAttributes.first())); + for (int i=1; i<filterAttributes.count(); ++i) { + query.append(QString(QLatin1String(" INTERSECT SELECT DISTINCT a.Name FROM IndexTable a, " + "IndexFilterTable b, FilterAttributeTable c WHERE a.Id=b.IndexId " + "AND b.FilterAttributeId=c.Id AND c.Name='%1'")) + .arg(quote(filterAttributes.at(i)))); + } + } + + m_query->exec(query); + while (m_query->next()) { + if (!m_query->value(0).toString().isEmpty()) + indices.append(m_query->value(0).toString()); + } + return indices; +} + +void QHelpDBReader::linksForKeyword(const QString &keyword, const QStringList &filterAttributes, + QMap<QString, QUrl> &linkMap) const +{ + if (!m_query) + return; + + QString query; + if (filterAttributes.isEmpty()) { + query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor " + "FROM IndexTable a, FileNameTable d, " + "FolderTable e, NamespaceTable f WHERE " + "a.FileId=d.FileId AND d.FolderId=e.Id AND a.NamespaceId=f.Id " + "AND a.Name='%1'")).arg(quote(keyword)); + } else if (m_useAttributesCache) { + query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor, a.Id " + "FROM IndexTable a, " + "FileNameTable d, FolderTable e, NamespaceTable f WHERE " + "a.FileId=d.FileId AND d.FolderId=e.Id " + "AND a.NamespaceId=f.Id AND a.Name='%1'")) + .arg(quote(keyword)); + m_query->exec(query); + while (m_query->next()) { + if (m_indicesCache.contains(m_query->value(5).toInt())) { + linkMap.insertMulti(m_query->value(0).toString(), buildQUrl(m_query->value(1).toString(), + m_query->value(2).toString(), m_query->value(3).toString(), + m_query->value(4).toString())); + } + } + return; + } else { + query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor " + "FROM IndexTable a, IndexFilterTable b, FilterAttributeTable c, " + "FileNameTable d, FolderTable e, NamespaceTable f " + "WHERE a.FileId=d.FileId AND d.FolderId=e.Id " + "AND a.NamespaceId=f.Id AND b.IndexId=a.Id AND b.FilterAttributeId=c.Id " + "AND a.Name='%1' AND c.Name='%2'")).arg(quote(keyword)) + .arg(quote(filterAttributes.first())); + for (int i=1; i<filterAttributes.count(); ++i) { + query.append(QString(QLatin1String(" INTERSECT SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor " + "FROM IndexTable a, IndexFilterTable b, FilterAttributeTable c, " + "FileNameTable d, FolderTable e, NamespaceTable f " + "WHERE a.FileId=d.FileId AND d.FolderId=e.Id " + "AND a.NamespaceId=f.Id AND b.IndexId=a.Id AND b.FilterAttributeId=c.Id " + "AND a.Name='%1' AND c.Name='%2'")).arg(quote(keyword)) + .arg(quote(filterAttributes.at(i)))); + } + } + + QString title; + m_query->exec(query); + while (m_query->next()) { + title = m_query->value(0).toString(); + if (title.isEmpty()) // generate a title + corresponding path + title = keyword + QLatin1String(" : ") + m_query->value(3).toString(); + linkMap.insertMulti(title, buildQUrl(m_query->value(1).toString(), + m_query->value(2).toString(), m_query->value(3).toString(), + m_query->value(4).toString())); + } +} + +void QHelpDBReader::linksForIdentifier(const QString &id, + const QStringList &filterAttributes, + QMap<QString, QUrl> &linkMap) const +{ + if (!m_query) + return; + + QString query; + if (filterAttributes.isEmpty()) { + query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor " + "FROM IndexTable a, FileNameTable d, FolderTable e, " + "NamespaceTable f WHERE a.FileId=d.FileId AND " + "d.FolderId=e.Id AND a.NamespaceId=f.Id AND a.Identifier='%1'")) + .arg(quote(id)); + } else if (m_useAttributesCache) { + query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor, a.Id " + "FROM IndexTable a," + "FileNameTable d, FolderTable e, NamespaceTable f WHERE " + "a.FileId=d.FileId AND d.FolderId=e.Id " + "AND a.NamespaceId=f.Id AND a.Identifier='%1'")) + .arg(quote(id)); + m_query->exec(query); + while (m_query->next()) { + if (m_indicesCache.contains(m_query->value(5).toInt())) { + linkMap.insertMulti(m_query->value(0).toString(), buildQUrl(m_query->value(1).toString(), + m_query->value(2).toString(), m_query->value(3).toString(), + m_query->value(4).toString())); + } + } + return; + } else { + query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor " + "FROM IndexTable a, IndexFilterTable b, FilterAttributeTable c, " + "FileNameTable d, FolderTable e, NamespaceTable f " + "WHERE a.FileId=d.FileId AND d.FolderId=e.Id " + "AND a.NamespaceId=f.Id AND b.IndexId=a.Id AND b.FilterAttributeId=c.Id " + "AND a.Identifier='%1' AND c.Name='%2'")).arg(quote(id)) + .arg(quote(filterAttributes.first())); + for (int i=0; i<filterAttributes.count(); ++i) { + query.append(QString(QLatin1String(" INTERSECT SELECT d.Title, f.Name, e.Name, " + "d.Name, a.Anchor FROM IndexTable a, IndexFilterTable b, " + "FilterAttributeTable c, FileNameTable d, " + "FolderTable e, NamespaceTable f WHERE " + "a.FileId=d.FileId AND d.FolderId=e.Id AND a.NamespaceId=f.Id " + "AND b.IndexId=a.Id AND b.FilterAttributeId=c.Id AND " + "a.Identifier='%1' AND c.Name='%2'")).arg(quote(id)) + .arg(quote(filterAttributes.at(i)))); + } + } + + m_query->exec(query); + while (m_query->next()) { + linkMap.insertMulti(m_query->value(0).toString(), buildQUrl(m_query->value(1).toString(), + m_query->value(2).toString(), m_query->value(3).toString(), + m_query->value(4).toString())); + } +} + +QUrl QHelpDBReader::buildQUrl(const QString &ns, const QString &folder, + const QString &relFileName, const QString &anchor) const +{ + QUrl url; + url.setScheme(QLatin1String("qthelp")); + url.setAuthority(ns); + url.setPath(folder + QLatin1Char('/') + relFileName); + url.setFragment(anchor); + return url; +} + +QList<QByteArray> QHelpDBReader::contentsForFilter(const QStringList &filterAttributes) const +{ + QList<QByteArray> contents; + if (!m_query) + return contents; + + //SELECT DISTINCT a.Data FROM ContentsTable a, ContentsFilterTable b, FilterAttributeTable c WHERE a.Id=b.ContentsId AND b.FilterAttributeId=c.Id AND c.Name='qt' INTERSECT SELECT DISTINCT a.Data FROM ContentsTable a, ContentsFilterTable b, FilterAttributeTable c WHERE a.Id=b.ContentsId AND b.FilterAttributeId=c.Id AND c.Name='3.3.8'; + + QString query; + if (filterAttributes.isEmpty()) { + query = QLatin1String("SELECT Data from ContentsTable"); + } else { + query = QString(QLatin1String("SELECT a.Data FROM ContentsTable a, " + "ContentsFilterTable b, FilterAttributeTable c " + "WHERE a.Id=b.ContentsId AND b.FilterAttributeId=c.Id " + "AND c.Name='%1'")).arg(quote(filterAttributes.first())); + for (int i=1; i<filterAttributes.count(); ++i) { + query.append(QString(QLatin1String(" INTERSECT SELECT a.Data FROM ContentsTable a, " + "ContentsFilterTable b, FilterAttributeTable c " + "WHERE a.Id=b.ContentsId AND b.FilterAttributeId=c.Id " + "AND c.Name='%1'")).arg(quote(filterAttributes.at(i)))); + } + } + + m_query->exec(query); + while (m_query->next()) { + contents.append(m_query->value(0).toByteArray()); + } + return contents; +} + +QUrl QHelpDBReader::urlOfPath(const QString &relativePath) const +{ + QUrl url; + if (!m_query) + return url; + + m_query->exec(QLatin1String("SELECT a.Name, b.Name FROM NamespaceTable a, " + "FolderTable b WHERE a.id=b.NamespaceId and a.Id=1")); + if (m_query->next()) { + QString rp = relativePath; + QString anchor; + int i = rp.indexOf(QLatin1Char('#')); + if (i > -1) { + rp = relativePath.left(i); + anchor = relativePath.mid(i+1); + } + url = buildQUrl(m_query->value(0).toString(), + m_query->value(1).toString(), rp, anchor); + } + return url; +} + +QStringList QHelpDBReader::files(const QStringList &filterAttributes, + const QString &extensionFilter) const +{ + QStringList lst; + if (!m_query) + return lst; + + QString query; + QString extension; + if (!extensionFilter.isEmpty()) + extension = QString(QLatin1String("AND b.Name like \'%.%1\'")).arg(extensionFilter); + + if (filterAttributes.isEmpty()) { + query = QString(QLatin1String("SELECT a.Name, b.Name FROM FolderTable a, " + "FileNameTable b WHERE b.FolderId=a.Id %1")) + .arg(extension); + } else { + query = QString(QLatin1String("SELECT a.Name, b.Name FROM FolderTable a, " + "FileNameTable b, FileFilterTable c, FilterAttributeTable d " + "WHERE b.FolderId=a.Id AND b.FileId=c.FileId " + "AND c.FilterAttributeId=d.Id AND d.Name=\'%1\' %2")) + .arg(quote(filterAttributes.first())).arg(extension); + for (int i=1; i<filterAttributes.count(); ++i) { + query.append(QString(QLatin1String(" INTERSECT SELECT a.Name, b.Name FROM " + "FolderTable a, FileNameTable b, FileFilterTable c, " + "FilterAttributeTable d WHERE b.FolderId=a.Id AND " + "b.FileId=c.FileId AND c.FilterAttributeId=d.Id AND " + "d.Name=\'%1\' %2")).arg(quote(filterAttributes.at(i))) + .arg(extension)); + } + } + m_query->exec(query); + while (m_query->next()) { + lst.append(m_query->value(0).toString() + QLatin1Char('/') + + m_query->value(1).toString()); + } + + return lst; +} + +QVariant QHelpDBReader::metaData(const QString &name) const +{ + QVariant v; + if (!m_query) + return v; + + m_query->prepare(QLatin1String("SELECT COUNT(Value), Value FROM MetaDataTable " + "WHERE Name=?")); + m_query->bindValue(0, name); + if (m_query->exec() && m_query->next() + && m_query->value(0).toInt() == 1) + v = m_query->value(1); + return v; +} + +QString QHelpDBReader::mergeList(const QStringList &list) const +{ + QString str; + foreach (QString s, list) + str.append(QLatin1Char('\'') + quote(s) + QLatin1String("\', ")); + if (str.endsWith(QLatin1String(", "))) + str = str.left(str.length()-2); + return str; +} + +QString QHelpDBReader::quote(const QString &string) const +{ + QString s = string; + s.replace(QLatin1Char('\''), QLatin1String("\'\'")); + return s; +} + +QSet<int> QHelpDBReader::indexIds(const QStringList &attributes) const +{ + QSet<int> ids; + + if (attributes.isEmpty()) + return ids; + + QString query = QString(QLatin1String("SELECT a.IndexId FROM IndexFilterTable a, " + "FilterAttributeTable b WHERE a.FilterAttributeId=b.Id " + "AND b.Name='%1'")).arg(attributes.first()); + for (int i=0; i<attributes.count(); ++i) { + query.append(QString(QLatin1String(" INTERSECT SELECT a.IndexId FROM " + "IndexFilterTable a, FilterAttributeTable b WHERE " + "a.FilterAttributeId=b.Id AND b.Name='%1'")) + .arg(attributes.at(i))); + } + + if (!m_query->exec(query)) + return ids; + + while (m_query->next()) + ids.insert(m_query->value(0).toInt()); + + return ids; +} + +bool QHelpDBReader::createAttributesCache(const QStringList &attributes, + const QSet<int> &indexIds) +{ + m_useAttributesCache = false; + + if (attributes.count() < 2) { + m_viewAttributes.clear(); + return true; + } + + bool needUpdate = !m_viewAttributes.count(); + + foreach (QString s, attributes) + m_viewAttributes.remove(s); + + if (m_viewAttributes.count() || needUpdate) { + m_viewAttributes.clear(); + m_indicesCache = indexIds; + } + foreach (QString s, attributes) + m_viewAttributes.insert(s); + m_useAttributesCache = true; + return true; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpdbreader_p.h b/tools/assistant/lib/qhelpdbreader_p.h new file mode 100644 index 0000000..08fc382 --- /dev/null +++ b/tools/assistant/lib/qhelpdbreader_p.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPDBREADER_H +#define QHELPDBREADER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QObject> +#include <QtCore/QStringList> +#include <QtCore/QUrl> +#include <QtCore/QByteArray> +#include <QtCore/QSet> + +QT_BEGIN_NAMESPACE + +class QSqlQuery; + +class QHelpDBReader : public QObject +{ + Q_OBJECT + +public: + QHelpDBReader(const QString &dbName); + QHelpDBReader(const QString &dbName, const QString &uniqueId, + QObject *parent); + ~QHelpDBReader(); + + bool init(); + + QString errorMessage() const; + + QString databaseName() const; + QString namespaceName() const; + QString virtualFolder() const; + QList<QStringList> filterAttributeSets() const; + QStringList files(const QStringList &filterAttributes, + const QString &extensionFilter = QString()) const; + bool fileExists(const QString &virtualFolder, const QString &filePath, + const QStringList &filterAttributes = QStringList()) const; + QByteArray fileData(const QString &virtualFolder, + const QString &filePath) const; + + QStringList customFilters() const; + QStringList filterAttributes(const QString &filterName = QString()) const; + QStringList indicesForFilter(const QStringList &filterAttributes) const; + void linksForKeyword(const QString &keyword, const QStringList &filterAttributes, + QMap<QString, QUrl> &linkMap) const; + + void linksForIdentifier(const QString &id, const QStringList &filterAttributes, + QMap<QString, QUrl> &linkMap) const; + + QList<QByteArray> contentsForFilter(const QStringList &filterAttributes) const; + QUrl urlOfPath(const QString &relativePath) const; + + QSet<int> indexIds(const QStringList &attributes) const; + bool createAttributesCache(const QStringList &attributes, + const QSet<int> &indexIds); + QVariant metaData(const QString &name) const; + +private: + void initObject(const QString &dbName, const QString &uniqueId); + QUrl buildQUrl(const QString &ns, const QString &folder, + const QString &relFileName, const QString &anchor) const; + QString mergeList(const QStringList &list) const; + QString quote(const QString &string) const; + + bool m_initDone; + QString m_dbName; + QString m_uniqueId; + QString m_error; + QSqlQuery *m_query; + mutable QString m_namespace; + QSet<QString> m_viewAttributes; + bool m_useAttributesCache; + QSet<int> m_indicesCache; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/lib/qhelpengine.cpp b/tools/assistant/lib/qhelpengine.cpp new file mode 100644 index 0000000..6a603b7 --- /dev/null +++ b/tools/assistant/lib/qhelpengine.cpp @@ -0,0 +1,212 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpengine.h" +#include "qhelpengine_p.h" +#include "qhelpdbreader_p.h" +#include "qhelpcontentwidget.h" +#include "qhelpindexwidget.h" +#include "qhelpsearchengine.h" +#include "qhelpcollectionhandler_p.h" + +#include <QtCore/QDir> +#include <QtCore/QFile> +#include <QtCore/QLibrary> +#include <QtCore/QPluginLoader> +#include <QtGui/QApplication> +#include <QtSql/QSqlQuery> + +QT_BEGIN_NAMESPACE + +QHelpEnginePrivate::QHelpEnginePrivate() + : QHelpEngineCorePrivate() + , contentModel(0) + , contentWidget(0) + , indexModel(0) + , indexWidget(0) + , searchEngine(0) +{ +} + +QHelpEnginePrivate::~QHelpEnginePrivate() +{ +} + +void QHelpEnginePrivate::init(const QString &collectionFile, + QHelpEngineCore *helpEngineCore) +{ + QHelpEngineCorePrivate::init(collectionFile, helpEngineCore); + + contentModel = new QHelpContentModel(this); + indexModel = new QHelpIndexModel(this); + + connect(helpEngineCore, SIGNAL(setupFinished()), + this, SLOT(applyCurrentFilter())); + connect(helpEngineCore, SIGNAL(currentFilterChanged(const QString&)), + this, SLOT(applyCurrentFilter())); + +} + +void QHelpEnginePrivate::applyCurrentFilter() +{ + if (!error.isEmpty()) + return; + contentModel->createContents(currentFilter); + indexModel->createIndex(currentFilter); +} + +void QHelpEnginePrivate::setContentsWidgetBusy() +{ + contentWidget->setCursor(Qt::WaitCursor); +} + +void QHelpEnginePrivate::unsetContentsWidgetBusy() +{ + contentWidget->unsetCursor(); +} + +void QHelpEnginePrivate::setIndexWidgetBusy() +{ + indexWidget->setCursor(Qt::WaitCursor); +} + +void QHelpEnginePrivate::unsetIndexWidgetBusy() +{ + indexWidget->unsetCursor(); +} + +void QHelpEnginePrivate::stopDataCollection() +{ + contentModel->invalidateContents(true); + indexModel->invalidateIndex(true); +} + + + +/*! + \class QHelpEngine + \since 4.4 + \inmodule QtHelp + \brief The QHelpEngine class provides access to contents and + indices of the help engine. + + +*/ + +/*! + Constructs a new help engine with the given \a parent. The help + engine uses the information stored in the \a collectionFile for + providing help. If the collection file does not already exist, + it will be created. +*/ +QHelpEngine::QHelpEngine(const QString &collectionFile, QObject *parent) + : QHelpEngineCore(d = new QHelpEnginePrivate(), parent) +{ + d->init(collectionFile, this); +} + +/*! + Destroys the help engine object. +*/ +QHelpEngine::~QHelpEngine() +{ + d->stopDataCollection(); +} + +/*! + Returns the content model. +*/ +QHelpContentModel *QHelpEngine::contentModel() const +{ + return d->contentModel; +} + +/*! + Returns the index model. +*/ +QHelpIndexModel *QHelpEngine::indexModel() const +{ + return d->indexModel; +} + +/*! + Returns the content widget. +*/ +QHelpContentWidget *QHelpEngine::contentWidget() +{ + if (!d->contentWidget) { + d->contentWidget = new QHelpContentWidget(); + d->contentWidget->setModel(d->contentModel); + connect(d->contentModel, SIGNAL(contentsCreationStarted()), + d, SLOT(setContentsWidgetBusy())); + connect(d->contentModel, SIGNAL(contentsCreated()), + d, SLOT(unsetContentsWidgetBusy())); + } + return d->contentWidget; +} + +/*! + Returns the index widget. +*/ +QHelpIndexWidget *QHelpEngine::indexWidget() +{ + if (!d->indexWidget) { + d->indexWidget = new QHelpIndexWidget(); + d->indexWidget->setModel(d->indexModel); + connect(d->indexModel, SIGNAL(indexCreationStarted()), + d, SLOT(setIndexWidgetBusy())); + connect(d->indexModel, SIGNAL(indexCreated()), + d, SLOT(unsetIndexWidgetBusy())); + } + return d->indexWidget; +} + +/*! + Returns the default search engine. +*/ +QHelpSearchEngine* QHelpEngine::searchEngine() +{ + if (!d->searchEngine) + d->searchEngine = new QHelpSearchEngine(this, this); + return d->searchEngine; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpengine.h b/tools/assistant/lib/qhelpengine.h new file mode 100644 index 0000000..9c80ff3 --- /dev/null +++ b/tools/assistant/lib/qhelpengine.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPENGINE_H +#define QHELPENGINE_H + +#include <QtHelp/qhelpenginecore.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Help) + +class QHelpContentModel; +class QHelpContentWidget; +class QHelpIndexModel; +class QHelpIndexWidget; +class QHelpEnginePrivate; +class QHelpSearchEngine; + +class QHELP_EXPORT QHelpEngine : public QHelpEngineCore +{ + Q_OBJECT + +public: + QHelpEngine(const QString &collectionFile, QObject *parent = 0); + ~QHelpEngine(); + + QHelpContentModel *contentModel() const; + QHelpIndexModel *indexModel() const; + + QHelpContentWidget *contentWidget(); + QHelpIndexWidget *indexWidget(); + + QHelpSearchEngine *searchEngine(); + +private: + QHelpEnginePrivate *d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/tools/assistant/lib/qhelpengine_p.h b/tools/assistant/lib/qhelpengine_p.h new file mode 100644 index 0000000..287329a --- /dev/null +++ b/tools/assistant/lib/qhelpengine_p.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPENGINE_P_H +#define QHELPENGINE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QMap> +#include <QtCore/QStringList> +#include <QtCore/QObject> + +QT_BEGIN_NAMESPACE + +class QSqlQuery; + +class QHelpEngineCore; +class QHelpDBReader; +class QHelpContentModel; +class QHelpContentWidget; +class QHelpIndexModel; +class QHelpIndexWidget; +class QHelpSearchEngine; +class QHelpCollectionHandler; + +class QHelpEngineCorePrivate : public QObject +{ + Q_OBJECT + +public: + QHelpEngineCorePrivate(); + virtual ~QHelpEngineCorePrivate(); + + virtual void init(const QString &collectionFile, + QHelpEngineCore *helpEngineCore); + + void clearMaps(); + bool setup(); + + QMap<QString, QHelpDBReader*> readerMap; + QMap<QString, QHelpDBReader*> fileNameReaderMap; + QMultiMap<QString, QHelpDBReader*> virtualFolderMap; + QStringList orderedFileNameList; + + QHelpCollectionHandler *collectionHandler; + QString currentFilter; + QString error; + bool needsSetup; + bool autoSaveFilter; + +protected: + QHelpEngineCore *q; + +private slots: + void errorReceived(const QString &msg); +}; + + +class QHelpEnginePrivate : public QHelpEngineCorePrivate +{ + Q_OBJECT + +public: + QHelpEnginePrivate(); + ~QHelpEnginePrivate(); + + void init(const QString &collectionFile, + QHelpEngineCore *helpEngineCore); + + QHelpContentModel *contentModel; + QHelpContentWidget *contentWidget; + + QHelpIndexModel *indexModel; + QHelpIndexWidget *indexWidget; + + QHelpSearchEngine *searchEngine; + + void stopDataCollection(); + + friend class QHelpContentProvider; + friend class QHelpContentModel; + friend class QHelpIndexProvider; + friend class QHelpIndexModel; + +public slots: + void setContentsWidgetBusy(); + void unsetContentsWidgetBusy(); + void setIndexWidgetBusy(); + void unsetIndexWidgetBusy(); + +private slots: + void applyCurrentFilter(); +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/assistant/lib/qhelpenginecore.cpp b/tools/assistant/lib/qhelpenginecore.cpp new file mode 100644 index 0000000..85bd9fd --- /dev/null +++ b/tools/assistant/lib/qhelpenginecore.cpp @@ -0,0 +1,727 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpenginecore.h" +#include "qhelpengine_p.h" +#include "qhelpdbreader_p.h" +#include "qhelpcollectionhandler_p.h" + +#include <QtCore/QDir> +#include <QtCore/QFile> +#include <QtCore/QLibrary> +#include <QtCore/QPluginLoader> +#include <QtCore/QFileInfo> +#include <QtCore/QThread> +#include <QtGui/QApplication> +#include <QtSql/QSqlQuery> + +QT_BEGIN_NAMESPACE + +QHelpEngineCorePrivate::QHelpEngineCorePrivate() +{ + QHelpGlobal::uniquifyConnectionName(QString(), this); + autoSaveFilter = true; +} + +void QHelpEngineCorePrivate::init(const QString &collectionFile, + QHelpEngineCore *helpEngineCore) +{ + q = helpEngineCore; + collectionHandler = new QHelpCollectionHandler(collectionFile, helpEngineCore); + connect(collectionHandler, SIGNAL(error(const QString&)), + this, SLOT(errorReceived(const QString&))); + needsSetup = true; +} + +QHelpEngineCorePrivate::~QHelpEngineCorePrivate() +{ + delete collectionHandler; + clearMaps(); +} + +void QHelpEngineCorePrivate::clearMaps() +{ + QMap<QString, QHelpDBReader*>::iterator it = readerMap.begin(); + while (it != readerMap.end()) { + delete it.value(); + ++it; + } + readerMap.clear(); + fileNameReaderMap.clear(); + virtualFolderMap.clear(); + orderedFileNameList.clear(); +} + +bool QHelpEngineCorePrivate::setup() +{ + error.clear(); + if (!needsSetup) + return true; + + needsSetup = false; + emit q->setupStarted(); + clearMaps(); + + if (!collectionHandler->openCollectionFile()) { + emit q->setupFinished(); + return false; + } + + const QHelpCollectionHandler::DocInfoList docList = + collectionHandler->registeredDocumentations(); + QFileInfo fi(collectionHandler->collectionFile()); + QString absFileName; + foreach(const QHelpCollectionHandler::DocInfo &info, docList) { + if (QDir::isAbsolutePath(info.fileName)) { + absFileName = info.fileName; + } else { + absFileName = QFileInfo(fi.absolutePath() + QDir::separator() + info.fileName) + .absoluteFilePath(); + } + QHelpDBReader *reader = new QHelpDBReader(absFileName, + QHelpGlobal::uniquifyConnectionName(info.fileName, this), this); + if (!reader->init()) { + emit q->warning(tr("Cannot open documentation file %1: %2!") + .arg(absFileName, reader->errorMessage())); + continue; + } + + readerMap.insert(info.namespaceName, reader); + fileNameReaderMap.insert(absFileName, reader); + virtualFolderMap.insert(info.folderName, reader); + orderedFileNameList.append(absFileName); + } + q->currentFilter(); + emit q->setupFinished(); + return true; +} + +void QHelpEngineCorePrivate::errorReceived(const QString &msg) +{ + error = msg; +} + + + +/*! + \class QHelpEngineCore + \since 4.4 + \inmodule QtHelp + \brief The QHelpEngineCore class provides the core functionality + of the help system. + + Before the help engine can be used, it must be initialized by + calling setupData(). At the beginning of the setup process the + signal setupStarted() is emitted. From this point on until + the signal setupFinished() is emitted, is the help data in an + undefined meaning unusable state. + + The core help engine can be used to perform different tasks. + By calling linksForIdentifier() the engine returns + urls specifying the file locations inside the help system. The + actual file data can then be retrived by calling fileData(). In + contrast to all other functions in this class, linksForIdentifier() + depends on the currently set custom filter. Depending on the filter, + the function may return different hits. + + Every help engine can contain any number of custom filters. A custom + filter is defined by a name and set of filter attributes and can be + added to the help engine by calling addCustomFilter(). Analogous, + it is removed by calling removeCustomFilter(). customFilters() returns + all defined filters. + + The help engine also offers the possiblity to set and read values + in a persistant way comparable to ini files or Windows registry + entries. For more information see setValue() or value(). + + This class does not offer any GUI components or functionality for + indices or contents. If you need one of those use QHelpEngine + instead. +*/ + +/*! + \fn void QHelpEngineCore::setupStarted() + + This signal is emitted when setup is started. +*/ + +/*! + \fn void QHelpEngineCore::setupFinished() + + This signal is emitted when the setup is complete. +*/ + +/*! + \fn void QHelpEngineCore::currentFilterChanged(const QString &newFilter) + + This signal is emitted when the current filter is changed to + \a newFilter. +*/ + +/*! + \fn void QHelpEngineCore::warning(const QString &msg) + + This signal is emitted when a non critical error occurs. + The warning message is stored in \a msg. +*/ + +/*! + Constructs a new core help engine with a \a parent. The help engine + uses the information stored in the \a collectionFile to provide help. + If the collection file does not exist yet, it'll be created. +*/ +QHelpEngineCore::QHelpEngineCore(const QString &collectionFile, QObject *parent) + : QObject(parent) +{ + d = new QHelpEngineCorePrivate(); + d->init(collectionFile, this); +} + +/*! + \internal +*/ +QHelpEngineCore::QHelpEngineCore(QHelpEngineCorePrivate *helpEngineCorePrivate, + QObject *parent) + : QObject(parent) +{ + d = helpEngineCorePrivate; +} + +/*! + Destructs the help engine. +*/ +QHelpEngineCore::~QHelpEngineCore() +{ + delete d; +} + +/*! + \property QHelpEngineCore::collectionFile + \brief the absolute file name of the collection file currently used. + \since 4.5 + + Setting this property leaves the help engine in an invalid state. It is + important to invoke setupData() or any getter function in order to setup + the help engine again. +*/ +QString QHelpEngineCore::collectionFile() const +{ + return d->collectionHandler->collectionFile(); +} + +void QHelpEngineCore::setCollectionFile(const QString &fileName) +{ + if (fileName == collectionFile()) + return; + + if (d->collectionHandler) { + delete d->collectionHandler; + d->collectionHandler = 0; + d->clearMaps(); + } + d->init(fileName, this); + d->needsSetup = true; +} + +/*! + Sets up the help engine by processing the information found + in the collection file and returns true if successful; otherwise + returns false. + + By calling the function, the help + engine is forced to initialize itself immediately. Most of + the times, this function does not have to be called + explicitly because getter functions which depend on a correctly + set up help engine do that themselves. + + \note \c{qsqlite4.dll} needs to be deployed with the application as the + help system uses the sqlite driver when loading help collections. +*/ +bool QHelpEngineCore::setupData() +{ + d->needsSetup = true; + return d->setup(); +} + +/*! + Creates the file \a fileName and copies all contents from + the current collection file into the newly created file, + and returns true if successful; otherwise returns false. + + The copying process makes sure that file references to Qt + Collection files (\c{.qch}) files are updated accordingly. +*/ +bool QHelpEngineCore::copyCollectionFile(const QString &fileName) +{ + if (!d->setup()) + return false; + return d->collectionHandler->copyCollectionFile(fileName); +} + +/*! + Returns the namespace name defined for the Qt compressed help file (.qch) + specified by its \a documentationFileName. If the file is not valid, an + empty string is returned. + + \sa documentationFileName() +*/ +QString QHelpEngineCore::namespaceName(const QString &documentationFileName) +{ + QHelpDBReader reader(documentationFileName, + QHelpGlobal::uniquifyConnectionName(QLatin1String("GetNamespaceName"), + QThread::currentThread()), 0); + if (reader.init()) + return reader.namespaceName(); + return QString(); +} + +/*! + Registers the Qt compressed help file (.qch) contained in the file + \a documentationFileName. One compressed help file, uniquely + identified by its namespace can only be registered once. + True is returned if the registration was successful, otherwise + false. + + \sa unregisterDocumentation(), error() +*/ +bool QHelpEngineCore::registerDocumentation(const QString &documentationFileName) +{ + d->error.clear(); + d->needsSetup = true; + return d->collectionHandler->registerDocumentation(documentationFileName); +} + +/*! + Unregisters the Qt compressed help file (.qch) identified by its + \a namespaceName from the help collection. Returns true + on success, otherwise false. + + \sa registerDocumentation(), error() +*/ +bool QHelpEngineCore::unregisterDocumentation(const QString &namespaceName) +{ + d->error.clear(); + d->needsSetup = true; + return d->collectionHandler->unregisterDocumentation(namespaceName); +} + +/*! + Returns the absolute file name of the Qt compressed help file (.qch) + identified by the \a namespaceName. If there is no Qt compressed help file + with the specified namespace registered, an empty string is returned. + + \sa namespaceName() +*/ +QString QHelpEngineCore::documentationFileName(const QString &namespaceName) +{ + QString res; + if (!d->setup()) + return res; + const QHelpCollectionHandler::DocInfoList docList = d->collectionHandler->registeredDocumentations(); + foreach(const QHelpCollectionHandler::DocInfo info, docList) { + if (info.namespaceName == namespaceName) { + QFileInfo fi(d->collectionHandler->collectionFile()); + fi.setFile(fi.absolutePath() + QDir::separator() + info.fileName); + res = QDir::cleanPath(fi.absoluteFilePath()); + break; + } + } + return res; +} + +/*! + Returns a list of all registered Qt compressed help files of the current collection file. + The returned names are the namespaces of the registered Qt compressed help files (.qch). +*/ +QStringList QHelpEngineCore::registeredDocumentations() const +{ + QStringList list; + if (!d->setup()) + return list; + const QHelpCollectionHandler::DocInfoList docList = d->collectionHandler->registeredDocumentations(); + foreach(const QHelpCollectionHandler::DocInfo info, docList) { + list.append(info.namespaceName); + } + return list; +} + +/*! + Returns a list of custom filters. + + \sa addCustomFilter(), removeCustomFilter() +*/ +QStringList QHelpEngineCore::customFilters() const +{ + if (!d->setup()) + return QStringList(); + return d->collectionHandler->customFilters(); +} + +/*! + Adds the new custom filter \a filterName. The filter attributes + are specified by \a attributes. The function returns false if + the filter can not be added, e.g. when the filter already exists. + + \sa customFilters(), removeCustomFilter() +*/ +bool QHelpEngineCore::addCustomFilter(const QString &filterName, + const QStringList &attributes) +{ + d->error.clear(); + d->needsSetup = true; + return d->collectionHandler->addCustomFilter(filterName, + attributes); +} + +/*! + Returns true if the filter \a filterName was removed successfully, + otherwise false. + + \sa addCustomFilter(), customFilters() +*/ +bool QHelpEngineCore::removeCustomFilter(const QString &filterName) +{ + d->error.clear(); + d->needsSetup = true; + return d->collectionHandler->removeCustomFilter(filterName); +} + +/*! + Returns a list of all defined filter attributes. +*/ +QStringList QHelpEngineCore::filterAttributes() const +{ + if (!d->setup()) + return QStringList(); + return d->collectionHandler->filterAttributes(); +} + +/*! + Returns a list of filter attributes used by the custom + filter \a filterName. +*/ +QStringList QHelpEngineCore::filterAttributes(const QString &filterName) const +{ + if (!d->setup()) + return QStringList(); + return d->collectionHandler->filterAttributes(filterName); +} + +/*! + \property QHelpEngineCore::currentFilter + \brief the name of the custom filter currently applied. + \since 4.5 + + Setting this property will save the new custom filter permanently in the + help collection file. To set a custom filter without saving it + permanently, disable the auto save filter mode. + + \sa autoSaveFilter() +*/ +QString QHelpEngineCore::currentFilter() const +{ + if (!d->setup()) + return QString(); + + if (d->currentFilter.isEmpty()) { + QString filter = + d->collectionHandler->customValue(QLatin1String("CurrentFilter"), + QString()).toString(); + if (!filter.isEmpty() + && d->collectionHandler->customFilters().contains(filter)) + d->currentFilter = filter; + } + return d->currentFilter; +} + +void QHelpEngineCore::setCurrentFilter(const QString &filterName) +{ + if (!d->setup() || filterName == d->currentFilter) + return; + d->currentFilter = filterName; + if (d->autoSaveFilter) { + d->collectionHandler->setCustomValue(QLatin1String("CurrentFilter"), + d->currentFilter); + } + emit currentFilterChanged(d->currentFilter); +} + +/*! + Returns a list of filter attributes for the different filter sections + defined in the Qt compressed help file with the given namespace + \a namespaceName. +*/ +QList<QStringList> QHelpEngineCore::filterAttributeSets(const QString &namespaceName) const +{ + if (d->setup()) { + QHelpDBReader *reader = d->readerMap.value(namespaceName); + if (reader) + return reader->filterAttributeSets(); + } + return QList<QStringList>(); +} + +/*! + Returns a list of files contained in the Qt compressed help file \a + namespaceName. The files can be filtered by \a filterAttributes as + well as by their extension \a extensionFilter (e.g. 'html'). +*/ +QList<QUrl> QHelpEngineCore::files(const QString namespaceName, + const QStringList &filterAttributes, + const QString &extensionFilter) +{ + QList<QUrl> res; + if (!d->setup()) + return res; + QHelpDBReader *reader = d->readerMap.value(namespaceName); + if (!reader) { + d->error = tr("The specified namespace does not exist!"); + return res; + } + + QUrl url; + url.setScheme(QLatin1String("qthelp")); + url.setAuthority(namespaceName); + + const QStringList files = reader->files(filterAttributes, extensionFilter); + foreach (const QString file, files) { + url.setPath(QLatin1String("/") + file); + res.append(url); + } + return res; +} + +/*! + Returns an invalid URL if the file \a url cannot be found. + If the file exists, either the same url is returned or a + different url if the file is located in a different namespace + which is merged via a common virtual folder. +*/ +QUrl QHelpEngineCore::findFile(const QUrl &url) const +{ + QUrl res; + if (!d->setup() || !url.isValid() || url.toString().count(QLatin1Char('/')) < 4 + || url.scheme() != QLatin1String("qthelp")) + return res; + + QString ns = url.authority(); + QString filePath = QDir::cleanPath(url.path()); + if (filePath.startsWith(QLatin1Char('/'))) + filePath = filePath.mid(1); + QString virtualFolder = filePath.mid(0, filePath.indexOf(QLatin1Char('/'), 1)); + filePath = filePath.mid(virtualFolder.length()+1); + + QHelpDBReader *defaultReader = 0; + if (d->readerMap.contains(ns)) { + defaultReader = d->readerMap.value(ns); + if (defaultReader->fileExists(virtualFolder, filePath)) + return url; + } + + QStringList filterAtts = filterAttributes(currentFilter()); + foreach (QHelpDBReader *reader, d->virtualFolderMap.values(virtualFolder)) { + if (reader == defaultReader) + continue; + if (reader->fileExists(virtualFolder, filePath, filterAtts)) { + res = url; + res.setAuthority(reader->namespaceName()); + return res; + } + } + + foreach (QHelpDBReader *reader, d->virtualFolderMap.values(virtualFolder)) { + if (reader == defaultReader) + continue; + if (reader->fileExists(virtualFolder, filePath)) { + res = url; + res.setAuthority(reader->namespaceName()); + break; + } + } + + return res; +} + +/*! + Returns the data of the file specified by \a url. If the + file does not exist, an empty QByteArray is returned. + + \sa findFile() +*/ +QByteArray QHelpEngineCore::fileData(const QUrl &url) const +{ + if (!d->setup() || !url.isValid() || url.toString().count(QLatin1Char('/')) < 4 + || url.scheme() != QLatin1String("qthelp")) + return QByteArray(); + + QString ns = url.authority(); + QString filePath = QDir::cleanPath(url.path()); + if (filePath.startsWith(QLatin1Char('/'))) + filePath = filePath.mid(1); + QString virtualFolder = filePath.mid(0, filePath.indexOf(QLatin1Char('/'), 1)); + filePath = filePath.mid(virtualFolder.length()+1); + + QByteArray ba; + QHelpDBReader *defaultReader = 0; + if (d->readerMap.contains(ns)) { + defaultReader = d->readerMap.value(ns); + ba = defaultReader->fileData(virtualFolder, filePath); + } + + if (ba.isEmpty()) { + foreach (QHelpDBReader *reader, d->virtualFolderMap.values(virtualFolder)) { + if (reader == defaultReader) + continue; + ba = reader->fileData(virtualFolder, filePath); + if (!ba.isEmpty()) + return ba; + } + } + return ba; +} + +/*! + Returns a map of hits found for the \a id. A hit contains the + title of the document and the url where the keyword is located. + The result depends on the current filter, meaning only the keywords + registered for the current filter will be returned. +*/ +QMap<QString, QUrl> QHelpEngineCore::linksForIdentifier(const QString &id) const +{ + QMap<QString, QUrl> linkMap; + if (!d->setup()) + return linkMap; + + QStringList atts = filterAttributes(d->currentFilter); + foreach (QHelpDBReader *reader, d->readerMap) + reader->linksForIdentifier(id, atts, linkMap); + + return linkMap; +} + +/*! + Removes the \a key from the settings section in the + collection file. Returns true if the value was removed + successfully, otherwise false. + + \sa customValue(), setCustomValue() +*/ +bool QHelpEngineCore::removeCustomValue(const QString &key) +{ + d->error.clear(); + return d->collectionHandler->removeCustomValue(key); +} + +/*! + Returns the value assigned to the \a key. If the requested + key does not exist, the specified \a defaultValue is + returned. + + \sa setCustomValue(), removeCustomValue() +*/ +QVariant QHelpEngineCore::customValue(const QString &key, const QVariant &defaultValue) const +{ + if (!d->setup()) + return QVariant(); + return d->collectionHandler->customValue(key, defaultValue); +} + +/*! + Save the \a value under the \a key. If the key already exist, + the value will be overwritten. Returns true if the value was + saved successfully, otherwise false. + + \sa customValue(), removeCustomValue() +*/ +bool QHelpEngineCore::setCustomValue(const QString &key, const QVariant &value) +{ + d->error.clear(); + return d->collectionHandler->setCustomValue(key, value); +} + +/*! + Returns the meta data for the Qt compressed help file \a + documentationFileName. If there is no data available for + \a name, an invalid QVariant() is returned. The meta + data is defined when creating the Qt compressed help file and + cannot be modified later. Common meta data includes e.g. + the author of the documentation. +*/ +QVariant QHelpEngineCore::metaData(const QString &documentationFileName, + const QString &name) +{ + QHelpDBReader reader(documentationFileName, QLatin1String("GetMetaData"), 0); + + if (reader.init()) + return reader.metaData(name); + return QVariant(); +} + +/*! + Returns a description of the last error that occured. +*/ +QString QHelpEngineCore::error() const +{ + return d->error; +} + +/*! + \property QHelpEngineCore::autoSaveFilter + \brief whether QHelpEngineCore is in auto save filter mode or not. + \since 4.5 + + If QHelpEngineCore is in auto save filter mode, the current filter is + automatically saved when it is changed by the setCurrentFilter() + function. The filter is saved persistently in the help collection file. + + By default, this mode is on. +*/ +void QHelpEngineCore::setAutoSaveFilter(bool save) +{ + d->autoSaveFilter = save; +} + +bool QHelpEngineCore::autoSaveFilter() const +{ + return d->autoSaveFilter; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpenginecore.h b/tools/assistant/lib/qhelpenginecore.h new file mode 100644 index 0000000..92ba2fd --- /dev/null +++ b/tools/assistant/lib/qhelpenginecore.h @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPENGINECORE_H +#define QHELPENGINECORE_H + +#include <QtHelp/qhelp_global.h> + +#include <QtCore/QUrl> +#include <QtCore/QMap> +#include <QtCore/QObject> +#include <QtCore/QVariant> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Help) + +class QHelpEngineCorePrivate; + +class QHELP_EXPORT QHelpEngineCore : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool autoSaveFilter READ autoSaveFilter WRITE setAutoSaveFilter) + Q_PROPERTY(QString collectionFile READ collectionFile WRITE setCollectionFile) + Q_PROPERTY(QString currentFilter READ currentFilter WRITE setCurrentFilter) + +public: + QHelpEngineCore(const QString &collectionFile, QObject *parent = 0); + virtual ~QHelpEngineCore(); + + bool setupData(); + + QString collectionFile() const; + void setCollectionFile(const QString &fileName); + + bool copyCollectionFile(const QString &fileName); + + static QString namespaceName(const QString &documentationFileName); + bool registerDocumentation(const QString &documentationFileName); + bool unregisterDocumentation(const QString &namespaceName); + QString documentationFileName(const QString &namespaceName); + + QStringList customFilters() const; + bool removeCustomFilter(const QString &filterName); + bool addCustomFilter(const QString &filterName, + const QStringList &attributes); + + QStringList filterAttributes() const; + QStringList filterAttributes(const QString &filterName) const; + + QString currentFilter() const; + void setCurrentFilter(const QString &filterName); + + QStringList registeredDocumentations() const; + QList<QStringList> filterAttributeSets(const QString &namespaceName) const; + QList<QUrl> files(const QString namespaceName, + const QStringList &filterAttributes, + const QString &extensionFilter = QString()); + QUrl findFile(const QUrl &url) const; + QByteArray fileData(const QUrl &url) const; + + QMap<QString, QUrl> linksForIdentifier(const QString &id) const; + + bool removeCustomValue(const QString &key); + QVariant customValue(const QString &key, + const QVariant &defaultValue = QVariant()) const; + bool setCustomValue(const QString &key, const QVariant &value); + + static QVariant metaData(const QString &documentationFileName, + const QString &name); + + QString error() const; + + void setAutoSaveFilter(bool save); + bool autoSaveFilter() const; + +Q_SIGNALS: + void setupStarted(); + void setupFinished(); + void currentFilterChanged(const QString &newFilter); + void warning(const QString &msg); + +protected: + QHelpEngineCore(QHelpEngineCorePrivate *helpEngineCorePrivate, + QObject *parent); + +private: + QHelpEngineCorePrivate *d; + friend class QHelpEngineCorePrivate; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QHELPENGINECORE_H diff --git a/tools/assistant/lib/qhelpgenerator.cpp b/tools/assistant/lib/qhelpgenerator.cpp new file mode 100644 index 0000000..03df3cc --- /dev/null +++ b/tools/assistant/lib/qhelpgenerator.cpp @@ -0,0 +1,823 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpgenerator_p.h" +#include "qhelpdatainterface_p.h" + +#include <math.h> +#include <QtCore/QFile> +#include <QtCore/QFileInfo> +#include <QtCore/QDir> +#include <QtCore/QDebug> +#include <QtCore/QVariant> +#include <QtCore/QDateTime> +#include <QtCore/QTextCodec> +#include <QtSql/QSqlQuery> + +QT_BEGIN_NAMESPACE + +class QHelpGeneratorPrivate +{ +public: + QHelpGeneratorPrivate(); + ~QHelpGeneratorPrivate(); + + QString error; + QSqlQuery *query; + + int namespaceId; + int virtualFolderId; + + QMap<QString, int> fileMap; + QMap<int, QSet<int> > fileFilterMap; + + double progress; + double oldProgress; + double contentStep; + double fileStep; + double indexStep; +}; + +QHelpGeneratorPrivate::QHelpGeneratorPrivate() +{ + query = 0; + namespaceId = -1; + virtualFolderId = -1; +} + +QHelpGeneratorPrivate::~QHelpGeneratorPrivate() +{ +} + + + +/*! + \internal + \class QHelpGenerator + \since 4.4 + \brief The QHelpGenerator class generates a new + Qt compressed help file (.qch). + + The help generator takes a help data structure as + input for generating a new Qt compressed help files. Since + the generation may takes some time, the generator emits + various signals to inform about its current state. +*/ + +/*! + \fn void QHelpGenerator::statusChanged(const QString &msg) + + This signal is emitted when the generation status changes. + The status is basically a specific task like inserting + files or building up the keyword index. The parameter + \a msg contains the detailed status description. +*/ + +/*! + \fn void QHelpGenerator::progressChanged(double progress) + + This signal is emitted when the progress changes. The + \a progress ranges from 0 to 100. +*/ + +/*! + \fn void QHelpGenerator::warning(const QString &msg) + + This signal is emitted when a non critical error occurs, + e.g. when a referenced file cannot be found. \a msg + contains the exact warning message. +*/ + +/*! + Constructs a new help generator with the give \a parent. +*/ +QHelpGenerator::QHelpGenerator(QObject *parent) + : QObject(parent) +{ + d = new QHelpGeneratorPrivate; +} + +/*! + Destructs the help generator. +*/ +QHelpGenerator::~QHelpGenerator() +{ + delete d; +} + +/*! + Takes the \a helpData and generates a new documentation + set from it. The Qt compressed help file is written to \a + outputFileName. Returns true on success, otherwise false. +*/ +bool QHelpGenerator::generate(QHelpDataInterface *helpData, + const QString &outputFileName) +{ + emit progressChanged(0); + d->error.clear(); + if (!helpData || helpData->namespaceName().isEmpty()) { + d->error = tr("Invalid help data!"); + return false; + } + + QString outFileName = outputFileName; + if (outFileName.isEmpty()) { + d->error = tr("No output file name specified!"); + return false; + } + + QFileInfo fi(outFileName); + if (fi.exists()) { + if (!fi.dir().remove(fi.fileName())) { + d->error = tr("The file %1 cannot be overwritten!").arg(outFileName); + return false; + } + } + + setupProgress(helpData); + + emit statusChanged(tr("Building up file structure...")); + bool openingOk = true; + { + QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), QLatin1String("builder")); + db.setDatabaseName(outFileName); + openingOk = db.open(); + if (openingOk) + d->query = new QSqlQuery(db); + } + + if (!openingOk) { + d->error = tr("Cannot open data base file %1!").arg(outFileName); + cleanupDB(); + return false; + } + + addProgress(1.0); + createTables(); + insertFileNotFoundFile(); + insertMetaData(helpData->metaData()); + + if (!registerVirtualFolder(helpData->virtualFolder(), helpData->namespaceName())) { + d->error = tr("Cannot register namespace %1!").arg(helpData->namespaceName()); + cleanupDB(); + return false; + } + addProgress(1.0); + + emit statusChanged(tr("Insert custom filters...")); + foreach (QHelpDataCustomFilter f, helpData->customFilters()) { + if (!registerCustomFilter(f.name, f.filterAttributes, true)) { + cleanupDB(); + return false; + } + } + addProgress(1.0); + + int i = 1; + QList<QHelpDataFilterSection>::const_iterator it = helpData->filterSections().constBegin(); + while (it != helpData->filterSections().constEnd()) { + emit statusChanged(tr("Insert help data for filter section (%1 of %2)...") + .arg(i++).arg(helpData->filterSections().count())); + insertFilterAttributes((*it).filterAttributes()); + QByteArray ba; + QDataStream s(&ba, QIODevice::WriteOnly); + foreach (QHelpDataContentItem *itm, (*it).contents()) + writeTree(s, itm, 0); + if (!insertFiles((*it).files(), helpData->rootPath(), (*it).filterAttributes()) + || !insertContents(ba, (*it).filterAttributes()) + || !insertKeywords((*it).indices(), (*it).filterAttributes())) { + cleanupDB(); + return false; + } + ++it; + } + + cleanupDB(); + emit progressChanged(100); + emit statusChanged(tr("Documentation successfully generated.")); + return true; +} + +void QHelpGenerator::setupProgress(QHelpDataInterface *helpData) +{ + d->progress = 0; + d->oldProgress = 0; + + int numberOfFiles = 0; + int numberOfIndices = 0; + QList<QHelpDataFilterSection>::const_iterator it = helpData->filterSections().constBegin(); + while (it != helpData->filterSections().constEnd()) { + numberOfFiles += (*it).files().count(); + numberOfIndices += (*it).indices().count(); + ++it; + } + // init 2% + // filters 1% + // contents 10% + // files 60% + // indices 27% + d->contentStep = 10.0/(double)helpData->customFilters().count(); + d->fileStep = 60.0/(double)numberOfFiles; + d->indexStep = 27.0/(double)numberOfIndices; +} + +void QHelpGenerator::addProgress(double step) +{ + d->progress += step; + if ((d->progress-d->oldProgress) >= 1.0 && d->progress <= 100.0) { + d->oldProgress = d->progress; + emit progressChanged(ceil(d->progress)); + } +} + +void QHelpGenerator::cleanupDB() +{ + if (d->query) { + d->query->clear(); + delete d->query; + d->query = 0; + } + QSqlDatabase::removeDatabase(QLatin1String("builder")); +} + +void QHelpGenerator::writeTree(QDataStream &s, QHelpDataContentItem *item, int depth) +{ + QString fReference = QDir::cleanPath(item->reference()); + if (fReference.startsWith(QLatin1String("./"))) + fReference = fReference.mid(2); + + s << depth; + s << fReference; + s << item->title(); + foreach (QHelpDataContentItem *i, item->children()) + writeTree(s, i, depth+1); +} + +/*! + Returns the last error message. +*/ +QString QHelpGenerator::error() const +{ + return d->error; +} + +bool QHelpGenerator::createTables() +{ + if (!d->query) + return false; + + d->query->exec(QLatin1String("SELECT COUNT(*) FROM sqlite_master WHERE TYPE=\'table\'" + "AND Name=\'NamespaceTable\'")); + d->query->next(); + if (d->query->value(0).toInt() > 0) { + d->error = tr("Some tables already exist!"); + return false; + } + + QStringList tables; + tables << QLatin1String("CREATE TABLE NamespaceTable (" + "Id INTEGER PRIMARY KEY," + "Name TEXT )") + << QLatin1String("CREATE TABLE FilterAttributeTable (" + "Id INTEGER PRIMARY KEY, " + "Name TEXT )") + << QLatin1String("CREATE TABLE FilterNameTable (" + "Id INTEGER PRIMARY KEY, " + "Name TEXT )") + << QLatin1String("CREATE TABLE FilterTable (" + "NameId INTEGER, " + "FilterAttributeId INTEGER )") + << QLatin1String("CREATE TABLE IndexTable (" + "Id INTEGER PRIMARY KEY, " + "Name TEXT, " + "Identifier TEXT, " + "NamespaceId INTEGER, " + "FileId INTEGER, " + "Anchor TEXT )") + << QLatin1String("CREATE TABLE IndexItemTable (" + "Id INTEGER, " + "IndexId INTEGER )") + << QLatin1String("CREATE TABLE IndexFilterTable (" + "FilterAttributeId INTEGER, " + "IndexId INTEGER )") + << QLatin1String("CREATE TABLE ContentsTable (" + "Id INTEGER PRIMARY KEY, " + "NamespaceId INTEGER, " + "Data BLOB )") + << QLatin1String("CREATE TABLE ContentsFilterTable (" + "FilterAttributeId INTEGER, " + "ContentsId INTEGER )") + << QLatin1String("CREATE TABLE FileAttributeSetTable (" + "Id INTEGER, " + "FilterAttributeId INTEGER )") + << QLatin1String("CREATE TABLE FileDataTable (" + "Id INTEGER PRIMARY KEY, " + "Data BLOB )") + << QLatin1String("CREATE TABLE FileFilterTable (" + "FilterAttributeId INTEGER, " + "FileId INTEGER )") + << QLatin1String("CREATE TABLE FileNameTable (" + "FolderId INTEGER, " + "Name TEXT, " + "FileId INTEGER, " + "Title TEXT )") + << QLatin1String("CREATE TABLE FolderTable(" + "Id INTEGER PRIMARY KEY, " + "Name Text, " + "NamespaceID INTEGER )") + << QLatin1String("CREATE TABLE MetaDataTable(" + "Name Text, " + "Value BLOB )"); + + foreach (QString q, tables) { + if (!d->query->exec(q)) { + d->error = tr("Cannot create tables!"); + return false; + } + } + + d->query->exec(QLatin1String("INSERT INTO MetaDataTable VALUES('qchVersion', '1.0')")); + + d->query->prepare(QLatin1String("INSERT INTO MetaDataTable VALUES('CreationDate', ?)")); + d->query->bindValue(0, QDateTime::currentDateTime().toString(Qt::ISODate)); + d->query->exec(); + + return true; +} + +bool QHelpGenerator::insertFileNotFoundFile() +{ + if (!d->query) + return false; + + d->query->exec(QLatin1String("SELECT id FROM FileNameTable WHERE Name=\'\'")); + if (d->query->next() && d->query->isValid()) + return true; + + d->query->prepare(QLatin1String("INSERT INTO FileDataTable VALUES (Null, ?)")); + d->query->bindValue(0, QByteArray()); + if (!d->query->exec()) + return false; + + int fileId = d->query->lastInsertId().toInt(); + d->query->prepare(QLatin1String("INSERT INTO FileNameTable (FolderId, Name, FileId, Title) " + " VALUES (0, '', ?, '')")); + d->query->bindValue(0, fileId); + if (fileId > -1 && d->query->exec()) { + d->fileMap.insert(QString(), fileId); + return true; + } + return false; +} + +bool QHelpGenerator::registerVirtualFolder(const QString &folderName, const QString &ns) +{ + if (!d->query || folderName.isEmpty() || ns.isEmpty()) + return false; + + d->query->prepare(QLatin1String("SELECT Id FROM FolderTable WHERE Name=?")); + d->query->bindValue(0, folderName); + d->query->exec(); + d->query->next(); + if (d->query->isValid() && d->query->value(0).toInt() > 0) + return true; + + d->namespaceId = -1; + d->query->prepare(QLatin1String("SELECT Id FROM NamespaceTable WHERE Name=?")); + d->query->bindValue(0, ns); + d->query->exec(); + while (d->query->next()) { + d->namespaceId = d->query->value(0).toInt(); + break; + } + + if (d->namespaceId < 0) { + d->query->prepare(QLatin1String("INSERT INTO NamespaceTable VALUES(NULL, ?)")); + d->query->bindValue(0, ns); + if (d->query->exec()) + d->namespaceId = d->query->lastInsertId().toInt(); + } + + if (d->namespaceId > 0) { + d->query->prepare(QLatin1String("SELECT Id FROM FolderTable WHERE Name=?")); + d->query->bindValue(0, folderName); + d->query->exec(); + while (d->query->next()) + d->virtualFolderId = d->query->value(0).toInt(); + + if (d->virtualFolderId > 0) + return true; + + d->query->prepare(QLatin1String("INSERT INTO FolderTable (NamespaceId, Name) " + "VALUES (?, ?)")); + d->query->bindValue(0, d->namespaceId); + d->query->bindValue(1, folderName); + if (d->query->exec()) { + d->virtualFolderId = d->query->lastInsertId().toInt(); + return d->virtualFolderId > 0; + } + } + d->error = tr("Cannot register virtual folder!"); + return false; +} + +bool QHelpGenerator::insertFiles(const QStringList &files, const QString &rootPath, + const QStringList &filterAttributes) +{ + if (!d->query) + return false; + + emit statusChanged(tr("Insert files...")); + QList<int> filterAtts; + foreach (QString filterAtt, filterAttributes) { + d->query->prepare(QLatin1String("SELECT Id FROM FilterAttributeTable WHERE Name=?")); + d->query->bindValue(0, filterAtt); + d->query->exec(); + if (d->query->next()) + filterAtts.append(d->query->value(0).toInt()); + } + + int filterSetId = -1; + d->query->exec(QLatin1String("SELECT MAX(Id) FROM FileAttributeSetTable")); + if (d->query->next()) + filterSetId = d->query->value(0).toInt(); + if (filterSetId < 0) + return false; + ++filterSetId; + foreach (int attId, filterAtts) { + d->query->prepare(QLatin1String("INSERT INTO FileAttributeSetTable VALUES(?, ?)")); + d->query->bindValue(0, filterSetId); + d->query->bindValue(1, attId); + d->query->exec(); + } + + QString title; + QString charSet; + QMap<int, QSet<int> > tmpFileFilterMap; + QList<FileNameTableData> fileNameDataList; + QList<QByteArray> fileDataList; + + int tableFileId = 1; + d->query->exec(QLatin1String("SELECT MAX(Id) FROM FileDataTable")); + if (d->query->next()) + tableFileId = d->query->value(0).toInt() + 1; + + FileNameTableData fileNameData; + + int i = 0; + foreach (QString file, files) { + QFileInfo fi(rootPath + QDir::separator() + file); + if (!fi.exists()) { + emit warning(tr("The file %1 does not exist! Skipping it.") + .arg(fi.absoluteFilePath())); + continue; + } + + QFile f(fi.absoluteFilePath()); + if (!f.open(QIODevice::ReadOnly)) { + emit warning(tr("Cannot open file %1! Skipping it.") + .arg(fi.absoluteFilePath())); + continue; + } + + title.clear(); + QByteArray data; + data = f.readAll(); + + if (fi.suffix() == QLatin1String("html") || fi.suffix() == QLatin1String("htm")) { + charSet = QHelpGlobal::charsetFromData(data); + QTextStream stream(&data); + stream.setCodec(QTextCodec::codecForName(charSet.toLatin1().constData())); + title = QHelpGlobal::documentTitle(stream.readAll()); + } else { + title = fi.fileName(); + } + + QString fName = QDir::cleanPath(file); + if (fName.startsWith(QLatin1String("./"))) + fName = fName.mid(2); + + int fileId = -1; + if (!d->fileMap.contains(fName)) { + fileDataList.append(qCompress(data)); + + fileNameData.name = fName; + fileNameData.fileId = tableFileId; + fileNameData.title = title; + fileNameDataList.append(fileNameData); + + d->fileMap.insert(fName, tableFileId); + d->fileFilterMap.insert(tableFileId, filterAtts.toSet()); + tmpFileFilterMap.insert(tableFileId, filterAtts.toSet()); + + ++tableFileId; + } else { + fileId = d->fileMap.value(fName); + foreach (int filter, filterAtts) { + if (!d->fileFilterMap.value(fileId).contains(filter) + && !tmpFileFilterMap.value(fileId).contains(filter)) { + d->fileFilterMap[fileId].insert(filter); + tmpFileFilterMap[fileId].insert(filter); + } + } + } + } + + if (tmpFileFilterMap.count()) { + d->query->exec(QLatin1String("BEGIN")); + QMap<int, QSet<int> >::const_iterator it = tmpFileFilterMap.constBegin(); + while (it != tmpFileFilterMap.constEnd()) { + QSet<int>::const_iterator i = it.value().constBegin(); + while (i != it.value().constEnd()) { + d->query->prepare(QLatin1String("INSERT INTO FileFilterTable VALUES(?, ?)")); + d->query->bindValue(0, *i); + d->query->bindValue(1, it.key()); + d->query->exec(); + ++i; + } + ++it; + } + + QList<QByteArray>::const_iterator fileIt = fileDataList.constBegin(); + while (fileIt != fileDataList.constEnd()) { + d->query->prepare(QLatin1String("INSERT INTO FileDataTable VALUES (Null, ?)")); + d->query->bindValue(0, *fileIt); + d->query->exec(); + ++fileIt; + if (++i%20 == 0) + addProgress(d->fileStep*20.0); + } + + QList<FileNameTableData>::const_iterator fileNameIt = fileNameDataList.constBegin(); + while (fileNameIt != fileNameDataList.constEnd()) { + d->query->prepare(QLatin1String("INSERT INTO FileNameTable (FolderId, Name, FileId, Title) " + " VALUES (?, ?, ?, ?)")); + d->query->bindValue(0, 1); + d->query->bindValue(1, (*fileNameIt).name); + d->query->bindValue(2, (*fileNameIt).fileId); + d->query->bindValue(3, (*fileNameIt).title); + d->query->exec(); + ++fileNameIt; + } + d->query->exec(QLatin1String("COMMIT")); + } + + d->query->exec(QLatin1String("SELECT MAX(Id) FROM FileDataTable")); + if (d->query->next() + && d->query->value(0).toInt() == tableFileId-1) { + addProgress(d->fileStep*(i%20)); + return true; + } + return false; +} + +bool QHelpGenerator::registerCustomFilter(const QString &filterName, const QStringList &filterAttribs, + bool forceUpdate) +{ + if (!d->query) + return false; + + d->query->exec(QLatin1String("SELECT Id, Name FROM FilterAttributeTable")); + QStringList idsToInsert = filterAttribs; + QMap<QString, int> attributeMap; + while (d->query->next()) { + attributeMap.insert(d->query->value(1).toString(), + d->query->value(0).toInt()); + if (idsToInsert.contains(d->query->value(1).toString())) + idsToInsert.removeAll(d->query->value(1).toString()); + } + + foreach (QString id, idsToInsert) { + d->query->prepare(QLatin1String("INSERT INTO FilterAttributeTable VALUES(NULL, ?)")); + d->query->bindValue(0, id); + d->query->exec(); + attributeMap.insert(id, d->query->lastInsertId().toInt()); + } + + int nameId = -1; + d->query->prepare(QLatin1String("SELECT Id FROM FilterNameTable WHERE Name=?")); + d->query->bindValue(0, filterName); + d->query->exec(); + while (d->query->next()) { + nameId = d->query->value(0).toInt(); + break; + } + + if (nameId < 0) { + d->query->prepare(QLatin1String("INSERT INTO FilterNameTable VALUES(NULL, ?)")); + d->query->bindValue(0, filterName); + if (d->query->exec()) + nameId = d->query->lastInsertId().toInt(); + } else if (!forceUpdate) { + d->error = tr("The filter %1 is already registered!").arg(filterName); + return false; + } + + if (nameId < 0) { + d->error = tr("Cannot register filter %1!").arg(filterName); + return false; + } + + d->query->prepare(QLatin1String("DELETE FROM FilterTable WHERE NameId=?")); + d->query->bindValue(0, nameId); + d->query->exec(); + + foreach (QString att, filterAttribs) { + d->query->prepare(QLatin1String("INSERT INTO FilterTable VALUES(?, ?)")); + d->query->bindValue(0, nameId); + d->query->bindValue(1, attributeMap[att]); + if (!d->query->exec()) + return false; + } + return true; +} + +bool QHelpGenerator::insertKeywords(const QList<QHelpDataIndexItem> keywords, + const QStringList &filterAttributes) +{ + if (!d->query) + return false; + + emit statusChanged(tr("Insert indices...")); + int indexId = 1; + d->query->exec(QLatin1String("SELECT MAX(Id) FROM IndexTable")); + if (d->query->next()) + indexId = d->query->value(0).toInt() + 1; + + QList<int> filterAtts; + foreach (QString filterAtt, filterAttributes) { + d->query->prepare(QLatin1String("SELECT Id FROM FilterAttributeTable WHERE Name=?")); + d->query->bindValue(0, filterAtt); + d->query->exec(); + if (d->query->next()) + filterAtts.append(d->query->value(0).toInt()); + } + + int pos = -1; + QString fileName; + QString anchor; + QString fName; + int fileId = 1; + QList<int> indexFilterTable; + + int i = 0; + d->query->exec(QLatin1String("BEGIN")); + foreach (QHelpDataIndexItem itm, keywords) { + pos = itm.reference.indexOf(QLatin1Char('#')); + fileName = itm.reference.left(pos); + if (pos > -1) + anchor = itm.reference.mid(pos+1); + else + anchor.clear(); + + fName = QDir::cleanPath(fileName); + if (fName.startsWith(QLatin1String("./"))) + fName = fName.mid(2); + + if (d->fileMap.contains(fName)) + fileId = d->fileMap.value(fName); + else + fileId = 1; + + d->query->prepare(QLatin1String("INSERT INTO IndexTable (Name, Identifier, NamespaceId, FileId, Anchor) " + "VALUES(?, ?, ?, ?, ?)")); + d->query->bindValue(0, itm.name); + d->query->bindValue(1, itm.identifier); + d->query->bindValue(2, d->namespaceId); + d->query->bindValue(3, fileId); + d->query->bindValue(4, anchor); + d->query->exec(); + + indexFilterTable.append(indexId++); + if (++i%100 == 0) + addProgress(d->indexStep*100.0); + } + d->query->exec(QLatin1String("COMMIT")); + + d->query->exec(QLatin1String("BEGIN")); + foreach (int idx, indexFilterTable) { + foreach (int a, filterAtts) { + d->query->prepare(QLatin1String("INSERT INTO IndexFilterTable (FilterAttributeId, IndexId) " + "VALUES(?, ?)")); + d->query->bindValue(0, a); + d->query->bindValue(1, idx); + d->query->exec(); + } + } + d->query->exec(QLatin1String("COMMIT")); + + d->query->exec(QLatin1String("SELECT COUNT(Id) FROM IndexTable")); + if (d->query->next() && d->query->value(0).toInt() >= keywords.count()) + return true; + return false; +} + +bool QHelpGenerator::insertContents(const QByteArray &ba, + const QStringList &filterAttributes) +{ + if (!d->query) + return false; + + emit statusChanged(tr("Insert contents...")); + d->query->prepare(QLatin1String("INSERT INTO ContentsTable (NamespaceId, Data) " + "VALUES(?, ?)")); + d->query->bindValue(0, d->namespaceId); + d->query->bindValue(1, ba); + d->query->exec(); + int contentId = d->query->lastInsertId().toInt(); + if (contentId < 1) { + d->error = tr("Cannot insert contents!"); + return false; + } + + // associate the filter attributes + foreach (QString filterAtt, filterAttributes) { + d->query->prepare(QLatin1String("INSERT INTO ContentsFilterTable (FilterAttributeId, ContentsId) " + "SELECT Id, ? FROM FilterAttributeTable WHERE Name=?")); + d->query->bindValue(0, contentId); + d->query->bindValue(1, filterAtt); + d->query->exec(); + if (!d->query->isActive()) { + d->error = tr("Cannot register contents!"); + return false; + } + } + addProgress(d->contentStep); + return true; +} + +bool QHelpGenerator::insertFilterAttributes(const QStringList &attributes) +{ + if (!d->query) + return false; + + d->query->exec(QLatin1String("SELECT Name FROM FilterAttributeTable")); + QSet<QString> atts; + while (d->query->next()) + atts.insert(d->query->value(0).toString()); + + foreach (QString s, attributes) { + if (!atts.contains(s)) { + d->query->prepare(QLatin1String("INSERT INTO FilterAttributeTable VALUES(NULL, ?)")); + d->query->bindValue(0, s); + d->query->exec(); + } + } + return true; +} + +bool QHelpGenerator::insertMetaData(const QMap<QString, QVariant> &metaData) +{ + if (!d->query) + return false; + + QMap<QString, QVariant>::const_iterator it = metaData.constBegin(); + while (it != metaData.constEnd()) { + d->query->prepare(QLatin1String("INSERT INTO MetaDataTable VALUES(?, ?)")); + d->query->bindValue(0, it.key()); + d->query->bindValue(1, it.value()); + d->query->exec(); + ++it; + } + return true; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpgenerator_p.h b/tools/assistant/lib/qhelpgenerator_p.h new file mode 100644 index 0000000..ddf2aed --- /dev/null +++ b/tools/assistant/lib/qhelpgenerator_p.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPGENERATOR_H +#define QHELPGENERATOR_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhelp_global.h" +#include "qhelpdatainterface_p.h" + +#include <QtCore/QObject> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QHelpGeneratorPrivate; + +class QHELP_EXPORT QHelpGenerator : public QObject +{ + Q_OBJECT + +public: + QHelpGenerator(QObject *parent = 0); + ~QHelpGenerator(); + + bool generate(QHelpDataInterface *helpData, + const QString &outputFileName); + QString error() const; + +Q_SIGNALS: + void statusChanged(const QString &msg); + void progressChanged(double progress); + void warning(const QString &msg); + +private: + struct FileNameTableData + { + QString name; + int fileId; + QString title; + }; + + void writeTree(QDataStream &s, QHelpDataContentItem *item, int depth); + bool createTables(); + bool insertFileNotFoundFile(); + bool registerCustomFilter(const QString &filterName, + const QStringList &filterAttribs, bool forceUpdate = false); + bool registerVirtualFolder(const QString &folderName, const QString &ns); + bool insertFilterAttributes(const QStringList &attributes); + bool insertKeywords(const QList<QHelpDataIndexItem> keywords, + const QStringList &filterAttributes); + bool insertFiles(const QStringList &files, const QString &rootPath, + const QStringList &filterAttributes); + bool insertContents(const QByteArray &ba, + const QStringList &filterAttributes); + bool insertMetaData(const QMap<QString, QVariant> &metaData); + void cleanupDB(); + void setupProgress(QHelpDataInterface *helpData); + void addProgress(double step); + + QHelpGeneratorPrivate *d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/tools/assistant/lib/qhelpindexwidget.cpp b/tools/assistant/lib/qhelpindexwidget.cpp new file mode 100644 index 0000000..7db9867 --- /dev/null +++ b/tools/assistant/lib/qhelpindexwidget.cpp @@ -0,0 +1,445 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpindexwidget.h" +#include "qhelpenginecore.h" +#include "qhelpengine_p.h" +#include "qhelpdbreader_p.h" + +#include <QtCore/QThread> +#include <QtCore/QMutex> +#include <QtGui/QListView> +#include <QtGui/QHeaderView> + +QT_BEGIN_NAMESPACE + +class QHelpIndexProvider : public QThread +{ +public: + QHelpIndexProvider(QHelpEnginePrivate *helpEngine); + ~QHelpIndexProvider(); + void collectIndices(const QString &customFilterName); + void stopCollecting(); + QStringList indices() const; + QList<QHelpDBReader*> activeReaders() const; + QSet<int> indexIds(QHelpDBReader *reader) const; + +private: + void run(); + + QHelpEnginePrivate *m_helpEngine; + QStringList m_indices; + QList<QHelpDBReader*> m_activeReaders; + QMap<QHelpDBReader*, QSet<int> > m_indexIds; + QStringList m_filterAttributes; + mutable QMutex m_mutex; + bool m_abort; +}; + +class QHelpIndexModelPrivate +{ +public: + QHelpIndexModelPrivate(QHelpEnginePrivate *hE) + { + helpEngine = hE; + indexProvider = new QHelpIndexProvider(helpEngine); + insertedRows = 0; + } + + QHelpEnginePrivate *helpEngine; + QHelpIndexProvider *indexProvider; + QStringList indices; + int insertedRows; + QString currentFilter; + QList<QHelpDBReader*> activeReaders; +}; + +static bool caseInsensitiveLessThan(const QString &as, const QString &bs) +{ + return QString::compare(as, bs, Qt::CaseInsensitive) < 0; +} + +QHelpIndexProvider::QHelpIndexProvider(QHelpEnginePrivate *helpEngine) + : QThread(helpEngine) +{ + m_helpEngine = helpEngine; + m_abort = false; +} + +QHelpIndexProvider::~QHelpIndexProvider() +{ + stopCollecting(); +} + +void QHelpIndexProvider::collectIndices(const QString &customFilterName) +{ + m_mutex.lock(); + m_filterAttributes = m_helpEngine->q->filterAttributes(customFilterName); + m_mutex.unlock(); + if (!isRunning()) { + start(LowPriority); + } else { + stopCollecting(); + start(LowPriority); + } +} + +void QHelpIndexProvider::stopCollecting() +{ + if (!isRunning()) + return; + m_mutex.lock(); + m_abort = true; + m_mutex.unlock(); + wait(); +} + +QStringList QHelpIndexProvider::indices() const +{ + QMutexLocker lck(&m_mutex); + return m_indices; +} + +QList<QHelpDBReader*> QHelpIndexProvider::activeReaders() const +{ + QMutexLocker lck(&m_mutex); + return m_activeReaders; +} + +QSet<int> QHelpIndexProvider::indexIds(QHelpDBReader *reader) const +{ + QMutexLocker lck(&m_mutex); + if (m_indexIds.contains(reader)) + return m_indexIds.value(reader); + return QSet<int>(); +} + +void QHelpIndexProvider::run() +{ + m_mutex.lock(); + QStringList atts = m_filterAttributes; + m_indices.clear(); + m_activeReaders.clear(); + QSet<QString> indicesSet; + m_mutex.unlock(); + + foreach (QString dbFileName, m_helpEngine->fileNameReaderMap.keys()) { + m_mutex.lock(); + if (m_abort) { + m_abort = false; + m_mutex.unlock(); + return; + } + m_mutex.unlock(); + QHelpDBReader reader(dbFileName, + QHelpGlobal::uniquifyConnectionName(dbFileName + + QLatin1String("FromIndexProvider"), + QThread::currentThread()), 0); + if (!reader.init()) + continue; + QStringList lst = reader.indicesForFilter(atts); + if (!lst.isEmpty()) { + m_mutex.lock(); + foreach (QString s, lst) + indicesSet.insert(s); + if (m_abort) { + m_abort = false; + m_mutex.unlock(); + return; + } + QHelpDBReader *orgReader = m_helpEngine->fileNameReaderMap.value(dbFileName); + m_indexIds.insert(orgReader, reader.indexIds(atts)); + m_activeReaders.append(orgReader); + m_mutex.unlock(); + } + } + m_mutex.lock(); + m_indices = indicesSet.values(); + qSort(m_indices.begin(), m_indices.end(), caseInsensitiveLessThan); + m_abort = false; + m_mutex.unlock(); +} + + + +/*! + \class QHelpIndexModel + \since 4.4 + \inmodule QtHelp + \brief The QHelpIndexModel class provides a model that + supplies index keywords to views. + + +*/ + +/*! + \fn void QHelpIndexModel::indexCreationStarted() + + This signal is emitted when the creation of a new index + has started. The current index is invalid from this + point on until the signal indexCreated() is emitted. + + \sa isCreatingIndex() +*/ + +/*! + \fn void QHelpIndexModel::indexCreated() + + This signal is emitted when the index has been created. +*/ + +QHelpIndexModel::QHelpIndexModel(QHelpEnginePrivate *helpEngine) + : QStringListModel(helpEngine) +{ + d = new QHelpIndexModelPrivate(helpEngine); + + connect(d->indexProvider, SIGNAL(finished()), this, SLOT(insertIndices())); + connect(helpEngine->q, SIGNAL(setupStarted()), this, SLOT(invalidateIndex())); +} + +QHelpIndexModel::~QHelpIndexModel() +{ + delete d; +} + +void QHelpIndexModel::invalidateIndex(bool onShutDown) +{ + if (onShutDown) + disconnect(this, SLOT(insertIndices())); + d->indexProvider->stopCollecting(); + d->indices.clear(); + filter(QString()); +} + +/*! + Creates a new index by querying the help system for + keywords for the specified \a customFilterName. +*/ +void QHelpIndexModel::createIndex(const QString &customFilterName) +{ + d->currentFilter = customFilterName; + d->indexProvider->collectIndices(customFilterName); + emit indexCreationStarted(); +} + +void QHelpIndexModel::insertIndices() +{ + d->indices = d->indexProvider->indices(); + d->activeReaders = d->indexProvider->activeReaders(); + QStringList attributes = d->helpEngine->q->filterAttributes(d->currentFilter); + if (attributes.count() > 1) { + foreach (QHelpDBReader *r, d->activeReaders) + r->createAttributesCache(attributes, d->indexProvider->indexIds(r)); + } + filter(QString()); + emit indexCreated(); +} + +/*! + Returns true if the index is currently built up, otherwise + false. +*/ +bool QHelpIndexModel::isCreatingIndex() const +{ + return d->indexProvider->isRunning(); +} + +/*! + Returns all hits found for the \a keyword. A hit consists of + the URL and the document title. +*/ +QMap<QString, QUrl> QHelpIndexModel::linksForKeyword(const QString &keyword) const +{ + QMap<QString, QUrl> linkMap; + QStringList filterAttributes = d->helpEngine->q->filterAttributes(d->currentFilter); + foreach (QHelpDBReader *reader, d->activeReaders) + reader->linksForKeyword(keyword, filterAttributes, linkMap); + return linkMap; +} + +/*! + Filters the indices and returns the model index of the best + matching keyword. In a first step, only the keywords containing + \a filter are kept in the model's index list. Analogously, if + \a wildcard is not empty, only the keywords matched are left + in the index list. In a second step, the best match is + determined and its index model returned. When specifying a + wildcard expression, the \a filter string is used to + search for the best match. +*/ +QModelIndex QHelpIndexModel::filter(const QString &filter, const QString &wildcard) +{ + if (filter.isEmpty()) { + setStringList(d->indices); + return index(-1, 0, QModelIndex()); + } + + QStringList lst; + int goodMatch = -1; + int perfectMatch = -1; + + if (!wildcard.isEmpty()) { + QRegExp regExp(wildcard, Qt::CaseInsensitive); + regExp.setPatternSyntax(QRegExp::Wildcard); + foreach (QString index, d->indices) { + if (index.contains(regExp)) { + lst.append(index); + if (perfectMatch == -1 && index.startsWith(filter, Qt::CaseInsensitive)) { + if (goodMatch == -1) + goodMatch = lst.count()-1; + if (filter.length() == index.length()){ + perfectMatch = lst.count()-1; + } + } else if (perfectMatch > -1 && index == filter) { + perfectMatch = lst.count()-1; + } + } + } + } else { + foreach (QString index, d->indices) { + if (index.contains(filter, Qt::CaseInsensitive)) { + lst.append(index); + if (perfectMatch == -1 && index.startsWith(filter, Qt::CaseInsensitive)) { + if (goodMatch == -1) + goodMatch = lst.count()-1; + if (filter.length() == index.length()){ + perfectMatch = lst.count()-1; + } + } else if (perfectMatch > -1 && index == filter) { + perfectMatch = lst.count()-1; + } + } + } + + } + + if (perfectMatch == -1) + perfectMatch = qMax(0, goodMatch); + + setStringList(lst); + return index(perfectMatch, 0, QModelIndex()); +} + + + +/*! + \class QHelpIndexWidget + \inmodule QtHelp + \since 4.4 + \brief The QHelpIndexWidget class provides a list view + displaying the QHelpIndexModel. +*/ + +/*! + \fn void QHelpIndexWidget::linkActivated(const QUrl &link, + const QString &keyword) + + This signal is emitted when an item is activated and its + associated \a link should be shown. To know where the link + belongs to, the \a keyword is given as a second paremeter. +*/ + +/*! + \fn void QHelpIndexWidget::linksActivated(const QMap<QString, QUrl> &links, + const QString &keyword) + + This signal is emitted when the item representing the \a keyword + is activated and the item has more than one link associated. + The \a links consist of the document title and their URL. +*/ + +QHelpIndexWidget::QHelpIndexWidget() + : QListView(0) +{ + setEditTriggers(QAbstractItemView::NoEditTriggers); + setUniformItemSizes(true); + connect(this, SIGNAL(activated(const QModelIndex&)), + this, SLOT(showLink(const QModelIndex&))); +} + +void QHelpIndexWidget::showLink(const QModelIndex &index) +{ + if (!index.isValid()) + return; + + QHelpIndexModel *indexModel = qobject_cast<QHelpIndexModel*>(model()); + if (!indexModel) + return; + QVariant v = indexModel->data(index, Qt::DisplayRole); + QString name; + if (v.isValid()) + name = v.toString(); + + QMap<QString, QUrl> links = indexModel->linksForKeyword(name); + if (links.count() == 1) { + emit linkActivated(links.constBegin().value(), name); + } else if (links.count() > 1) { + emit linksActivated(links, name); + } +} + +/*! + Activates the current item which will result eventually in + the emitting of a linkActivated() or linksActivated() + signal. +*/ +void QHelpIndexWidget::activateCurrentItem() +{ + showLink(currentIndex()); +} + +/*! + Filters the indices according to \a filter or \a wildcard. + The item with the best match is set as current item. + + \sa QHelpIndexModel::filter() +*/ +void QHelpIndexWidget::filterIndices(const QString &filter, const QString &wildcard) +{ + QHelpIndexModel *indexModel = qobject_cast<QHelpIndexModel*>(model()); + if (!indexModel) + return; + QModelIndex idx = indexModel->filter(filter, wildcard); + if (idx.isValid()) + setCurrentIndex(idx); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpindexwidget.h b/tools/assistant/lib/qhelpindexwidget.h new file mode 100644 index 0000000..46b9e4c --- /dev/null +++ b/tools/assistant/lib/qhelpindexwidget.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPINDEXWIDGET_H +#define QHELPINDEXWIDGET_H + +#include <QtHelp/qhelp_global.h> + +#include <QtCore/QUrl> +#include <QtGui/QStringListModel> +#include <QtGui/QListView> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Help) + +class QHelpEnginePrivate; +class QHelpIndexModelPrivate; + +class QHELP_EXPORT QHelpIndexModel : public QStringListModel +{ + Q_OBJECT + +public: + void createIndex(const QString &customFilterName); + QModelIndex filter(const QString &filter, + const QString &wildcard = QString()); + + QMap<QString, QUrl> linksForKeyword(const QString &keyword) const; + bool isCreatingIndex() const; + +Q_SIGNALS: + void indexCreationStarted(); + void indexCreated(); + +private Q_SLOTS: + void insertIndices(); + void invalidateIndex(bool onShutDown = false); + +private: + QHelpIndexModel(QHelpEnginePrivate *helpEngine); + ~QHelpIndexModel(); + + QHelpIndexModelPrivate *d; + friend class QHelpEnginePrivate; +}; + +class QHELP_EXPORT QHelpIndexWidget : public QListView +{ + Q_OBJECT + +Q_SIGNALS: + void linkActivated(const QUrl &link, const QString &keyword); + void linksActivated(const QMap<QString, QUrl> &links, + const QString &keyword); + +public Q_SLOTS: + void filterIndices(const QString &filter, + const QString &wildcard = QString()); + void activateCurrentItem(); + +private Q_SLOTS: + void showLink(const QModelIndex &index); + +private: + QHelpIndexWidget(); + friend class QHelpEngine; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/tools/assistant/lib/qhelpprojectdata.cpp b/tools/assistant/lib/qhelpprojectdata.cpp new file mode 100644 index 0000000..fcb8cf6 --- /dev/null +++ b/tools/assistant/lib/qhelpprojectdata.cpp @@ -0,0 +1,374 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpprojectdata_p.h" + +#include <QtCore/QFileInfo> +#include <QtCore/QStack> +#include <QtCore/QMap> +#include <QtCore/QVariant> +#include <QtXml/QXmlStreamReader> + +QT_BEGIN_NAMESPACE + +class QHelpProjectDataPrivate : public QXmlStreamReader +{ +public: + void readData(const QByteArray &contents); + + QString virtualFolder; + QString namespaceName; + QString rootPath; + + QStringList fileList; + QList<QHelpDataCustomFilter> customFilterList; + QList<QHelpDataFilterSection> filterSectionList; + QMap<QString, QVariant> metaData; + + QString errorMsg; + +private: + void readProject(); + void readCustomFilter(); + void readFilterSection(); + void readTOC(); + void readKeywords(); + void readFiles(); + void raiseUnknownTokenError(); +}; + +void QHelpProjectDataPrivate::raiseUnknownTokenError() +{ + raiseError(QObject::tr("Unknown token.")); +} + +void QHelpProjectDataPrivate::readData(const QByteArray &contents) +{ + addData(contents); + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("QtHelpProject") + && attributes().value(QLatin1String("version")) == QLatin1String("1.0")) + readProject(); + else + raiseError(QObject::tr("Unknown token. Expected \"QtHelpProject\"!")); + } + } + + if (hasError()) { + raiseError(QObject::tr("Error in line %1: %2").arg(lineNumber()) + .arg(errorString())); + } +} + +void QHelpProjectDataPrivate::readProject() +{ + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("virtualFolder")) { + virtualFolder = readElementText(); + if (virtualFolder.contains(QLatin1String("/"))) + raiseError(QObject::tr("A virtual folder must not contain a \'/\' character!")); + } else if (name() == QLatin1String("namespace")) { + namespaceName = readElementText(); + if (namespaceName.contains(QLatin1String("/"))) + raiseError(QObject::tr("A namespace must not contain a \'/\' character!")); + } else if (name() == QLatin1String("customFilter")) { + readCustomFilter(); + } else if (name() == QLatin1String("filterSection")) { + readFilterSection(); + } else if (name() == QLatin1String("metaData")) { + QString n = attributes().value(QLatin1String("name")).toString(); + if (!metaData.contains(n)) + metaData[n] = attributes().value(QLatin1String("value")).toString(); + else + metaData.insert(n, attributes().value(QLatin1String("value")).toString()); + } else { + raiseUnknownTokenError(); + } + } else if (isEndElement() && name() == QLatin1String("QtHelpProject")) { + if (namespaceName.isEmpty()) + raiseError(QObject::tr("Missing namespace in QtHelpProject.")); + else if (virtualFolder.isEmpty()) + raiseError(QObject::tr("Missing virtual folder in QtHelpProject")); + break; + } + } +} + +void QHelpProjectDataPrivate::readCustomFilter() +{ + QHelpDataCustomFilter filter; + filter.name = attributes().value(QLatin1String("name")).toString(); + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("filterAttribute")) + filter.filterAttributes.append(readElementText()); + else + raiseUnknownTokenError(); + } else if (isEndElement() && name() == QLatin1String("customFilter")) { + break; + } + } + customFilterList.append(filter); +} + +void QHelpProjectDataPrivate::readFilterSection() +{ + filterSectionList.append(QHelpDataFilterSection()); + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("filterAttribute")) + filterSectionList.last().addFilterAttribute(readElementText()); + else if (name() == QLatin1String("toc")) + readTOC(); + else if (name() == QLatin1String("keywords")) + readKeywords(); + else if (name() == QLatin1String("files")) + readFiles(); + else + raiseUnknownTokenError(); + } else if (isEndElement() && name() == QLatin1String("filterSection")) { + break; + } + } +} + +void QHelpProjectDataPrivate::readTOC() +{ + QStack<QHelpDataContentItem*> contentStack; + QHelpDataContentItem *itm = 0; + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("section")) { + QString title = attributes().value(QLatin1String("title")).toString(); + QString ref = attributes().value(QLatin1String("ref")).toString(); + if (contentStack.isEmpty()) { + itm = new QHelpDataContentItem(0, title, ref); + filterSectionList.last().addContent(itm); + } else { + itm = new QHelpDataContentItem(contentStack.top(), title, ref); + } + contentStack.push(itm); + } else { + raiseUnknownTokenError(); + } + } else if (isEndElement()) { + if (name() == QLatin1String("section")) { + contentStack.pop(); + continue; + } else if (name() == QLatin1String("toc") && contentStack.isEmpty()) { + break; + } else { + raiseUnknownTokenError(); + } + } + } +} + +void QHelpProjectDataPrivate::readKeywords() +{ + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("keyword")) { + if (attributes().value(QLatin1String("ref")).toString().isEmpty() + || (attributes().value(QLatin1String("name")).toString().isEmpty() + && attributes().value(QLatin1String("id")).toString().isEmpty())) + raiseError(QObject::tr("Missing attribute in keyword at line %1.") + .arg(lineNumber())); + filterSectionList.last().addIndex( + QHelpDataIndexItem(attributes().value(QLatin1String("name")).toString(), + attributes().value(QLatin1String("id")).toString(), + attributes().value(QLatin1String("ref")).toString())); + } else { + raiseUnknownTokenError(); + } + } else if (isEndElement()) { + if (name() == QLatin1String("keyword")) + continue; + else if (name() == QLatin1String("keywords")) + break; + else + raiseUnknownTokenError(); + } + } +} + +void QHelpProjectDataPrivate::readFiles() +{ + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("file")) + filterSectionList.last().addFile(readElementText()); + else + raiseUnknownTokenError(); + } else if (isEndElement()) { + if (name() == QLatin1String("file")) + continue; + else if (name() == QLatin1String("files")) + break; + else + raiseUnknownTokenError(); + } + } +} + + + +/*! + \internal + \class QHelpProjectData + \since 4.4 + \brief The QHelpProjectData class stores all information found + in a Qt help project file. + + The structure is filled with data by calling readData(). The + specified file has to have the Qt help project file format in + order to be read successfully. Possible reading errors can be + retrieved by calling errorMessage(). +*/ + +/*! + Constructs a Qt help project data structure. +*/ +QHelpProjectData::QHelpProjectData() +{ + d = new QHelpProjectDataPrivate; +} + +/*! + Destroys the help project data. +*/ +QHelpProjectData::~QHelpProjectData() +{ + delete d; +} + +/*! + Reads the file \a fileName and stores the help data. The file has to + have the Qt help project file format. Returns true if the file + was successfully read, otherwise false. + + \sa errorMessage() +*/ +bool QHelpProjectData::readData(const QString &fileName) +{ + d->rootPath = QFileInfo(fileName).absolutePath(); + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly)) { + d->errorMsg = QObject::tr("The input file %1 could not be opened!") + .arg(fileName); + return false; + } + + d->readData(file.readAll()); + return !d->hasError(); +} + +/*! + Returns an error message if the reading of the Qt help project + file failed. Otherwise, an empty QString is returned. + + \sa readData() +*/ +QString QHelpProjectData::errorMessage() const +{ + if (d->hasError()) + return d->errorString(); + return d->errorMsg; +} + +/*! + \reimp +*/ +QString QHelpProjectData::namespaceName() const +{ + return d->namespaceName; +} + +/*! + \reimp +*/ +QString QHelpProjectData::virtualFolder() const +{ + return d->virtualFolder; +} + +/*! + \reimp +*/ +QList<QHelpDataCustomFilter> QHelpProjectData::customFilters() const +{ + return d->customFilterList; +} + +/*! + \reimp +*/ +QList<QHelpDataFilterSection> QHelpProjectData::filterSections() const +{ + return d->filterSectionList; +} + +/*! + \reimp +*/ +QMap<QString, QVariant> QHelpProjectData::metaData() const +{ + return d->metaData; +} + +/*! + \reimp +*/ +QString QHelpProjectData::rootPath() const +{ + return d->rootPath; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpprojectdata_p.h b/tools/assistant/lib/qhelpprojectdata_p.h new file mode 100644 index 0000000..52eb723 --- /dev/null +++ b/tools/assistant/lib/qhelpprojectdata_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPPROJECTDATA_H +#define QHELPPROJECTDATA_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhelp_global.h" +#include "qhelpdatainterface_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QHelpProjectDataPrivate; + +class QHELP_EXPORT QHelpProjectData : public QHelpDataInterface +{ +public: + QHelpProjectData(); + ~QHelpProjectData(); + + bool readData(const QString &fileName); + QString errorMessage() const; + + QString namespaceName() const; + QString virtualFolder() const; + QList<QHelpDataCustomFilter> customFilters() const; + QList<QHelpDataFilterSection> filterSections() const; + QMap<QString, QVariant> metaData() const; + QString rootPath() const; + +private: + QHelpProjectDataPrivate *d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/tools/assistant/lib/qhelpsearchengine.cpp b/tools/assistant/lib/qhelpsearchengine.cpp new file mode 100644 index 0000000..9025f4f --- /dev/null +++ b/tools/assistant/lib/qhelpsearchengine.cpp @@ -0,0 +1,445 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpenginecore.h" +#include "qhelpsearchengine.h" +#include "qhelpsearchquerywidget.h" +#include "qhelpsearchresultwidget.h" + +#if defined(QT_CLUCENE_SUPPORT) +# include "qhelpsearchindexreader_clucene_p.h" +# include "qhelpsearchindexwriter_clucene_p.h" +#else +# include "qhelpsearchindexreader_default_p.h" +# include "qhelpsearchindexwriter_default_p.h" +#endif + +#include <QtCore/QDir> +#include <QtCore/QFile> +#include <QtCore/QFileInfo> +#include <QtCore/QVariant> +#include <QtCore/QThread> +#include <QtCore/QPointer> + +QT_BEGIN_NAMESPACE + +#if defined(QT_CLUCENE_SUPPORT) + using namespace qt::fulltextsearch::clucene; +#else + using namespace qt::fulltextsearch::std; +#endif + +class QHelpSearchEnginePrivate : public QObject +{ + Q_OBJECT + +signals: + void indexingStarted(); + void indexingFinished(); + + void searchingStarted(); + void searchingFinished(int hits); + +private: + QHelpSearchEnginePrivate(QHelpEngineCore *helpEngine) + : queryWidget(0) + , resultWidget(0) + , helpEngine(helpEngine) + { + hitList.clear(); + indexReader = 0; + indexWriter = 0; + } + + ~QHelpSearchEnginePrivate() + { + hitList.clear(); + delete indexReader; + delete indexWriter; + } + + int hitsCount() const + { + int count = 0; + if (indexReader) + count = indexReader->hitsCount(); + + return count; + } + + QList<QHelpSearchEngine::SearchHit> hits(int start, int end) const + { + QList<QHelpSearchEngine::SearchHit> returnValue; + if (indexReader) { + for (int i = start; i < end && i < hitsCount(); ++i) + returnValue.append(indexReader->hit(i)); + } + return returnValue; + } + + void updateIndex(bool reindex = false) + { + if (helpEngine.isNull()) + return; + + if (!QFile::exists(QFileInfo(helpEngine->collectionFile()).path())) + return; + + if (!indexWriter) { + indexWriter = new QHelpSearchIndexWriter(); + + connect(indexWriter, SIGNAL(indexingStarted()), this, SIGNAL(indexingStarted())); + connect(indexWriter, SIGNAL(indexingFinished()), this, SIGNAL(indexingFinished())); + connect(indexWriter, SIGNAL(indexingFinished()), this, SLOT(optimizeIndex())); + } + + if (indexWriter) { + indexWriter->cancelIndexing(); + indexWriter->updateIndex(helpEngine->collectionFile(), + indexFilesFolder(), reindex); + } + } + + void cancelIndexing() + { + if (indexWriter) + indexWriter->cancelIndexing(); + } + + void search(const QList<QHelpSearchQuery> &queryList) + { + if (helpEngine.isNull()) + return; + + if (!QFile::exists(QFileInfo(helpEngine->collectionFile()).path())) + return; + + if (!indexReader) { + indexReader = new QHelpSearchIndexReader(); + + connect(indexReader, SIGNAL(searchingStarted()), this, SIGNAL(searchingStarted())); + connect(indexReader, SIGNAL(searchingFinished(int)), this, SIGNAL(searchingFinished(int))); + } + + if (indexReader) { + m_queryList = queryList; + indexReader->cancelSearching(); + indexReader->search(helpEngine->collectionFile(), indexFilesFolder(), queryList); + } + } + + void cancelSearching() + { + if (indexReader) + indexReader->cancelSearching(); + } + + QString indexFilesFolder() const + { + QString indexFilesFolder = QLatin1String(".fulltextsearch"); + if (helpEngine && !helpEngine->collectionFile().isEmpty()) { + QFileInfo fi(helpEngine->collectionFile()); + indexFilesFolder = fi.absolutePath() + QDir::separator() + + QLatin1Char('.') + + fi.fileName().left(fi.fileName().lastIndexOf(QLatin1String(".qhc"))); + } + return indexFilesFolder; + } + +private slots: + void optimizeIndex() + { +#if defined(QT_CLUCENE_SUPPORT) + if (indexWriter && !helpEngine.isNull()) { + indexWriter->optimizeIndex(); + } +#endif + } + +private: + friend class QHelpSearchEngine; + + QHelpSearchQueryWidget *queryWidget; + QHelpSearchResultWidget *resultWidget; + + QHelpSearchIndexReader *indexReader; + QHelpSearchIndexWriter *indexWriter; + + QPointer<QHelpEngineCore> helpEngine; + QList<QHelpSearchEngine::SearchHit> hitList; + + QList<QHelpSearchQuery> m_queryList; +}; + +#include "qhelpsearchengine.moc" + + +/*! + \class QHelpSearchQuery + \since 4.4 + \inmodule QtHelp + \brief The QHelpSearchQuery class contains the field name and the associated + search term + + The QHelpSearchQuery class contains the field name and the associated search + term. Depending on the field the search term might get split up into seperate + terms to be parsed differently by the search engine. + + \sa QHelpSearchQueryWidget +*/ + +/*! + \fn QHelpSearchQuery::QHelpSearchQuery() + + Constructs a new empty QHelpSearchQuery. +*/ + +/*! + \fn QHelpSearchQuery::QHelpSearchQuery(FieldName field, const QStringList &wordList) + + Constructs a new QHelpSearchQuery and initializes it with the given \a field and \a wordList. +*/ + +/*! + \enum QHelpSearchQuery::FieldName + This enum type specifies the field names that are handled by the search engine. + + \value DEFAULT the default field provided by the search widget, several terms should be + splitted and stored in the wordlist except search terms enclosed in quotes. + \value FUZZY a field only provided in use with clucene. Terms should be split in seperate + words and passed to the search engine. + \value WITHOUT a field only provided in use with clucene. Terms should be split in seperate + words and passed to the search engine. + \value PHRASE a field only provided in use with clucene. Terms should not be split in seperate + words. + \value ALL a field only provided in use with clucene. Terms should be split in seperate + words and passed to the search engine + \value ATLEAST a field only provided in use with clucene. Terms should be split in seperate + words and passed to the search engine +*/ + +/*! + \class QHelpSearchEngine + \since 4.4 + \inmodule QtHelp + \brief The QHelpSearchEngine class provides access to widgets reusable + to integrate fulltext search as well as to index and search documentation. + + Before the search engine can be used, one has to instantiate at least a + QHelpEngineCore object that needs to be passed to the search engines constructor. + This is required as the search engine needs to be connected to the help + engines setupFinished() signal to know when it can start to index documentation. + + After starting the indexing process the signal indexingStarted() is emitted and + on the end of the indexing process the indexingFinished() is emited. To stop + the indexing one can call cancelIndexing(). + + While the indexing process has finished, the search engine can now be used to search + thru its index for a given term. To do this one may use the possibility of creating the + QHelpSearchQuery list by self or reuse the QHelpSearchQueryWidget which has the inbuild + functionality to set up a proper search querys list that get's passed to the search engines + search() function. + + After the list of querys has been passed to the search engine, the signal searchingStarted() + is emited and after the search has finished the searchingFinished() signal is emited. The + search process can be stopped by calling cancelSearching(). + + If the search succeeds, the searchingFinished() will be called with the search hits count, + which can be reused to fetch the search hits from the search engine. Calling the hits() + function with the range of hits you would like to get will return a list of the requested + SearchHits. They basically constist at the moment of a pair of strings where the values + of that pair are the documentation file path and the page title. + + To display the given hits use the QHelpSearchResultWidget or build up your own one if you need + more advanced functionality. Note that the QHelpSearchResultWidget can not be instantiated + directly, you must retrieve the widget from the search engine in use as all connections will be + established for you by the widget itself. +*/ + +/*! + \fn void QHelpSearchEngine::indexingStarted() + + This signal is emitted when indexing process is started. +*/ + +/*! + \fn void QHelpSearchEngine::indexingFinished() + + This signal is emitted when the indexing process is complete. +*/ + +/*! + \fn void QHelpSearchEngine::searchingStarted() + + This signal is emitted when the search process is started. +*/ + +/*! + \fn void QHelpSearchEngine::searchingFinished(int hits) + + This signal is emitted when the search process is complete. + The hit count is stored in \a hits. +*/ + +/*! + Constructs a new search engine with the given \a parent. The search engine + uses the given \a helpEngine to access the documentation that needs to be indexed. + The QHelpEngine's setupFinished() signal is automatically connected to the + QHelpSearchEngine's indexing function, so that new documentation will be indexed + after the signal is emited. +*/ +QHelpSearchEngine::QHelpSearchEngine(QHelpEngineCore *helpEngine, QObject *parent) + : QObject(parent) +{ + d = new QHelpSearchEnginePrivate(helpEngine); + + connect(helpEngine, SIGNAL(setupFinished()), this, SLOT(indexDocumentation())); + + connect(d, SIGNAL(indexingStarted()), this, SIGNAL(indexingStarted())); + connect(d, SIGNAL(indexingFinished()), this, SIGNAL(indexingFinished())); + connect(d, SIGNAL(searchingStarted()), this, SIGNAL(searchingStarted())); + connect(d, SIGNAL(searchingFinished(int)), this, SIGNAL(searchingFinished(int))); +} + +/*! + Destructs the search engine. +*/ +QHelpSearchEngine::~QHelpSearchEngine() +{ + delete d; +} + +/*! + Returns a widget to use as input widget. Depending on your search engine + configuration you will get a different widget with more or less subwidgets. +*/ +QHelpSearchQueryWidget* QHelpSearchEngine::queryWidget() +{ + if (!d->queryWidget) + d->queryWidget = new QHelpSearchQueryWidget(); + + return d->queryWidget; +} + +/*! + Returns a widget that can hold and display the search results. +*/ +QHelpSearchResultWidget* QHelpSearchEngine::resultWidget() +{ + if (!d->resultWidget) + d->resultWidget = new QHelpSearchResultWidget(this); + + return d->resultWidget; +} + +/*! + Returns the amount of hits the search engine found. +*/ +int QHelpSearchEngine::hitsCount() const +{ + return d->hitsCount(); +} + +/*! + \typedef QHelpSearchEngine::SearchHit + + Typedef for QPair<QString, QString>. + The values of that pair are the documentation file path and the page title. + + \sa hits() +*/ + +/*! + Returns a list of search hits within the range of \a start \a end. +*/ +QList<QHelpSearchEngine::SearchHit> QHelpSearchEngine::hits(int start, int end) const +{ + return d->hits(start, end); +} + +/*! + Returns the list of queries last searched for. + \since 4.5 +*/ +QList<QHelpSearchQuery> QHelpSearchEngine::query() const +{ + return d->m_queryList; +} + +/*! + Forces the search engine to reindex all documentation files. +*/ +void QHelpSearchEngine::reindexDocumentation() +{ + d->updateIndex(true); +} + +/*! + Stops the indexing process. +*/ +void QHelpSearchEngine::cancelIndexing() +{ + d->cancelIndexing(); +} + +/*! + Stops the search process. +*/ +void QHelpSearchEngine::cancelSearching() +{ + d->cancelSearching(); +} + +/*! + Starts the search process using the given list of querys \a queryList + build by the search field name and the values to search for. +*/ +void QHelpSearchEngine::search(const QList<QHelpSearchQuery> &queryList) +{ + d->search(queryList); +} + +void QHelpSearchEngine::indexDocumentation() +{ + d->updateIndex(); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpsearchengine.h b/tools/assistant/lib/qhelpsearchengine.h new file mode 100644 index 0000000..bd14d3e --- /dev/null +++ b/tools/assistant/lib/qhelpsearchengine.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHENGINE_H +#define QHELPSEARCHENGINE_H + +#include <QtHelp/qhelp_global.h> + +#include <QtCore/QMap> +#include <QtCore/QUrl> +#include <QtCore/QObject> +#include <QtCore/QString> +#include <QtCore/QStringList> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Help) + +class QHelpEngineCore; +class QHelpSearchQueryWidget; +class QHelpSearchResultWidget; +class QHelpSearchEnginePrivate; + +class QHELP_EXPORT QHelpSearchQuery +{ +public: + enum FieldName { DEFAULT = 0, FUZZY, WITHOUT, PHRASE, ALL, ATLEAST }; + + QHelpSearchQuery() + : fieldName(DEFAULT) { wordList.clear(); } + QHelpSearchQuery(FieldName field, const QStringList &wordList) + : fieldName(field), wordList(wordList) {} + + FieldName fieldName; + QStringList wordList; +}; + +class QHELP_EXPORT QHelpSearchEngine : public QObject +{ + Q_OBJECT + +public: + QHelpSearchEngine(QHelpEngineCore *helpEngine, QObject *parent = 0); + ~QHelpSearchEngine(); + + QHelpSearchQueryWidget* queryWidget(); + QHelpSearchResultWidget* resultWidget(); + + int hitsCount() const; + + typedef QPair<QString, QString> SearchHit; + QList<SearchHit> hits(int start, int end) const; + + QList<QHelpSearchQuery> query() const; + +public Q_SLOTS: + void reindexDocumentation(); + void cancelIndexing(); + + void search(const QList<QHelpSearchQuery> &queryList); + void cancelSearching(); + +Q_SIGNALS: + void indexingStarted(); + void indexingFinished(); + + void searchingStarted(); + void searchingFinished(int hits); + +private Q_SLOTS: + void indexDocumentation(); + +private: + QHelpSearchEnginePrivate *d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QHELPSEARCHENGINE_H diff --git a/tools/assistant/lib/qhelpsearchindex_default.cpp b/tools/assistant/lib/qhelpsearchindex_default.cpp new file mode 100644 index 0000000..defba91 --- /dev/null +++ b/tools/assistant/lib/qhelpsearchindex_default.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpsearchindex_default_p.h" + +QT_BEGIN_NAMESPACE + +QDataStream &operator>>(QDataStream &s, Document &l) +{ + s >> l.docNumber; + s >> l.frequency; + return s; +} + +QDataStream &operator<<(QDataStream &s, const Document &l) +{ + s << qint16(l.docNumber); + s << qint16(l.frequency); + return s; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpsearchindex_default_p.h b/tools/assistant/lib/qhelpsearchindex_default_p.h new file mode 100644 index 0000000..b9ada2d --- /dev/null +++ b/tools/assistant/lib/qhelpsearchindex_default_p.h @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHINDEXDEFAULT_H +#define QHELPSEARCHINDEXDEFAULT_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QString> +#include <QtCore/QVector> +#include <QtCore/QDataStream> + +QT_BEGIN_NAMESPACE + +namespace QtHelpInternal { + +struct Document { + Document(qint16 d, qint16 f) + : docNumber(d), frequency(f) {} + + Document() + : docNumber(-1), frequency(0) {} + + bool operator==(const Document &doc) const { + return docNumber == doc.docNumber; + } + bool operator<(const Document &doc) const { + return frequency > doc.frequency; + } + bool operator<=(const Document &doc) const { + return frequency >= doc.frequency; + } + bool operator>(const Document &doc) const { + return frequency < doc.frequency; + } + + qint16 docNumber; + qint16 frequency; +}; + +struct DocumentInfo : public Document { + DocumentInfo() + : Document(-1, 0), documentTitle(QString()), documentUrl(QString()) {} + + DocumentInfo(qint16 d, qint16 f, const QString &title, const QString &url) + : Document(d, f), documentTitle(title), documentUrl(url) {} + + DocumentInfo(const Document &document, const QString &title, const QString &url) + : Document(document.docNumber, document.frequency), documentTitle(title), documentUrl(url) {} + + QString documentTitle; + QString documentUrl; +}; + +struct Entry { + Entry(qint16 d) { documents.append(Document(d, 1)); } + Entry(QVector<Document> l) : documents(l) {} + + QVector<Document> documents; +}; + +struct PosEntry { + PosEntry(int p) { positions.append(p); } + QList<uint> positions; +}; + +struct Term { + Term() : frequency(-1) {} + Term(const QString &t, int f, QVector<Document> l) : term(t), frequency(f), documents(l) {} + QString term; + int frequency; + QVector<Document>documents; + bool operator<(const Term &i2) const { return frequency < i2.frequency; } +}; + +struct TermInfo { + TermInfo() : frequency(-1) {} + TermInfo(const QString &t, int f, QVector<DocumentInfo> l) + : term(t), frequency(f), documents(l) {} + + bool operator<(const TermInfo &i2) const { return frequency < i2.frequency; } + + QString term; + int frequency; + QVector<DocumentInfo>documents; +}; + +} // namespace QtHelpInternal + +using QtHelpInternal::Document; +using QtHelpInternal::DocumentInfo; +using QtHelpInternal::Entry; +using QtHelpInternal::PosEntry; +using QtHelpInternal::Term; +using QtHelpInternal::TermInfo; + +QDataStream &operator>>(QDataStream &s, Document &l); +QDataStream &operator<<(QDataStream &s, const Document &l); + +QT_END_NAMESPACE + +#endif // QHELPSEARCHINDEXDEFAULT_H diff --git a/tools/assistant/lib/qhelpsearchindexreader_clucene.cpp b/tools/assistant/lib/qhelpsearchindexreader_clucene.cpp new file mode 100644 index 0000000..82a3a17 --- /dev/null +++ b/tools/assistant/lib/qhelpsearchindexreader_clucene.cpp @@ -0,0 +1,392 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpenginecore.h" +#include "fulltextsearch/qsearchable_p.h" +#include "fulltextsearch/qqueryparser_p.h" +#include "fulltextsearch/qindexreader_p.h" +#include "qhelpsearchindexreader_clucene_p.h" + +#include <QtCore/QDir> +#include <QtCore/QSet> +#include <QtCore/QString> +#include <QtCore/QFileInfo> +#include <QtCore/QStringList> +#include <QtCore/QTextStream> +#include <QtCore/QMutexLocker> + +QT_BEGIN_NAMESPACE + +namespace qt { + namespace fulltextsearch { + namespace clucene { + +QHelpSearchIndexReader::QHelpSearchIndexReader() + : QThread() + , m_cancel(false) +{ + // nothing todo +} + +QHelpSearchIndexReader::~QHelpSearchIndexReader() +{ + mutex.lock(); + this->m_cancel = true; + waitCondition.wakeOne(); + mutex.unlock(); + + wait(); +} + +void QHelpSearchIndexReader::cancelSearching() +{ + mutex.lock(); + this->m_cancel = true; + mutex.unlock(); +} + +void QHelpSearchIndexReader::search(const QString &collectionFile, + const QString &indexFilesFolder, + const QList<QHelpSearchQuery> &queryList) +{ + QMutexLocker lock(&mutex); + + this->hitList.clear(); + this->m_cancel = false; + this->m_query = queryList; + this->m_collectionFile = collectionFile; + this->m_indexFilesFolder = indexFilesFolder; + + start(QThread::NormalPriority); +} + +int QHelpSearchIndexReader::hitsCount() const +{ + return hitList.count(); +} + +QHelpSearchEngine::SearchHit QHelpSearchIndexReader::hit(int index) const +{ + return hitList.at(index); +} + +void QHelpSearchIndexReader::run() +{ + mutex.lock(); + + if (m_cancel) { + mutex.unlock(); + return; + } + + const QString collectionFile(this->m_collectionFile); + const QList<QHelpSearchQuery> &queryList = this->m_query; + const QString indexPath(m_indexFilesFolder); + + mutex.unlock(); + + QHelpEngineCore engine(collectionFile, 0); + if (!engine.setupData()) + return; + + QFileInfo fInfo(indexPath); + if (fInfo.exists() && !fInfo.isWritable()) { + qWarning("Full Text Search, could not read index (missing permissions)."); + return; + } + + if(QCLuceneIndexReader::indexExists(indexPath)) { + mutex.lock(); + if (m_cancel) { + mutex.unlock(); + return; + } + mutex.unlock(); + + emit searchingStarted(); + +#if !defined(QT_NO_EXCEPTIONS) + try { +#endif + QCLuceneBooleanQuery booleanQuery; + if (!buildQuery(booleanQuery, queryList)) { + emit searchingFinished(0); + return; + } + + const QStringList attribList = engine.filterAttributes(engine.currentFilter()); + if (!attribList.isEmpty()) { + QCLuceneStandardAnalyzer analyzer; + QCLuceneQuery* query = QCLuceneQueryParser::parse(QLatin1String("+") + + attribList.join(QLatin1String(" +")), QLatin1String("attribute"), + analyzer); + + if (!query) { + emit searchingFinished(0); + return; + } + booleanQuery.add(query, true, true, false); + } + + QCLuceneIndexSearcher indexSearcher(indexPath); + QCLuceneHits hits = indexSearcher.search(booleanQuery); + const QStringList namespaceList = engine.registeredDocumentations(); + + QSet<QString> pathSet; + QCLuceneDocument document; + for (qint32 i = 0; i < hits.length(); i++) { + document = hits.document(i); + const QString path = document.get(QLatin1String("path")); + if (!pathSet.contains(path) && namespaceList.contains( + document.get(QLatin1String("namespace")), Qt::CaseInsensitive)) { + pathSet.insert(path); + hitList.append(qMakePair(path, document.get(QLatin1String("title")))); + } + document.clear(); + + mutex.lock(); + if (m_cancel) { + mutex.unlock(); + emit searchingFinished(0); + return; + } + mutex.unlock(); + } + + indexSearcher.close(); + int count = hitList.count(); + if (count > 0) + boostSearchHits(engine, hitList, queryList); + emit searchingFinished(hitList.count()); + +#if !defined(QT_NO_EXCEPTIONS) + } catch(...) { + hitList.clear(); + emit searchingFinished(0); + } +#endif + } +} + +bool QHelpSearchIndexReader::defaultQuery(const QString &term, + QCLuceneBooleanQuery &booleanQuery) +{ + QCLuceneStandardAnalyzer analyzer; + + const QLatin1String c("content"); + const QLatin1String t("titleTokenized"); + + QCLuceneQuery *query = QCLuceneQueryParser::parse(term, c, analyzer); + QCLuceneQuery *query2 = QCLuceneQueryParser::parse(term, t, analyzer); + if (query && query2) { + booleanQuery.add(query, true, false, false); + booleanQuery.add(query2, true, false, false); + return true; + } + + return false; +} + +bool QHelpSearchIndexReader::buildQuery(QCLuceneBooleanQuery &booleanQuery, + const QList<QHelpSearchQuery> &queryList) +{ + foreach (const QHelpSearchQuery query, queryList) { + switch (query.fieldName) { + case QHelpSearchQuery::FUZZY: { + const QLatin1String fuzzy("~"); + foreach (const QString term, query.wordList) { + if (term.isEmpty() || !defaultQuery(term.toLower() + fuzzy, booleanQuery)) + return false; + } + } break; + + case QHelpSearchQuery::WITHOUT: { + QStringList stopWords = QCLuceneStopAnalyzer().englishStopWords(); + foreach (const QString term, query.wordList) { + if (stopWords.contains(term, Qt::CaseInsensitive)) + continue; + + QCLuceneQuery *query = new QCLuceneTermQuery(QCLuceneTerm( + QLatin1String("content"), term.toLower())); + QCLuceneQuery *query2 = new QCLuceneTermQuery(QCLuceneTerm( + QLatin1String("titleTokenized"), term.toLower())); + + if (query && query2) { + booleanQuery.add(query, true, false, true); + booleanQuery.add(query2, true, false, true); + } else { + return false; + } + } + } break; + + case QHelpSearchQuery::PHRASE: { + const QString term = query.wordList.at(0).toLower(); + if (term.contains(QLatin1Char(' '))) { + QStringList termList = term.split(QLatin1String(" ")); + QCLucenePhraseQuery *q = new QCLucenePhraseQuery(); + QStringList stopWords = QCLuceneStopAnalyzer().englishStopWords(); + foreach (const QString t, termList) { + if (!stopWords.contains(t, Qt::CaseInsensitive)) + q->addTerm(QCLuceneTerm(QLatin1String("content"), t.toLower())); + } + booleanQuery.add(q, true, true, false); + } else { + QCLuceneQuery *query = new QCLuceneTermQuery(QCLuceneTerm( + QLatin1String("content"), term.toLower())); + QCLuceneQuery *query2 = new QCLuceneTermQuery(QCLuceneTerm( + QLatin1String("titleTokenized"), term.toLower())); + + if (query && query2) { + booleanQuery.add(query, true, true, false); + booleanQuery.add(query2, true, false, false); + } else { + return false; + } + } + } break; + + case QHelpSearchQuery::ALL: { + QStringList stopWords = QCLuceneStopAnalyzer().englishStopWords(); + foreach (const QString term, query.wordList) { + if (stopWords.contains(term, Qt::CaseInsensitive)) + continue; + + QCLuceneQuery *query = new QCLuceneTermQuery(QCLuceneTerm( + QLatin1String("content"), term.toLower())); + + if (query) { + booleanQuery.add(query, true, true, false); + } else { + return false; + } + } + } break; + + case QHelpSearchQuery::DEFAULT: { + QCLuceneStandardAnalyzer analyzer; + foreach (const QString t, query.wordList) { + QCLuceneQuery *query = QCLuceneQueryParser::parse(t.toLower(), + QLatin1String("content"), analyzer); + + if (query) + booleanQuery.add(query, true, true, false); + } + } break; + + case QHelpSearchQuery::ATLEAST: { + foreach (const QString term, query.wordList) { + if (term.isEmpty() || !defaultQuery(term.toLower(), booleanQuery)) + return false; + } + } + } + } + + return true; +} + +void QHelpSearchIndexReader::boostSearchHits(const QHelpEngineCore &engine, + QList<QHelpSearchEngine::SearchHit> &hitList, + const QList<QHelpSearchQuery> &queryList) +{ + foreach (const QHelpSearchQuery query, queryList) { + if (query.fieldName != QHelpSearchQuery::DEFAULT) + continue; + + QString joinedQuery = query.wordList.join(QLatin1String(" ")); + + QCLuceneStandardAnalyzer analyzer; + QCLuceneQuery *parsedQuery = QCLuceneQueryParser::parse( + joinedQuery, QLatin1String("content"), analyzer); + + if (parsedQuery) { + joinedQuery = parsedQuery->toString(); + delete parsedQuery; + } + + int length = QString(QLatin1String("content:")).length(); + int index = joinedQuery.indexOf(QLatin1String("content:")); + + QString term; + int nextIndex = 0; + QStringList searchTerms; + while (index != -1) { + nextIndex = joinedQuery.indexOf(QLatin1String("content:"), index + 1); + term = joinedQuery.mid(index + length, nextIndex - (length + index)) + .simplified(); + if (term.startsWith(QLatin1String("\"")) + && term.endsWith(QLatin1String("\""))) { + searchTerms.append(term.remove(QLatin1String("\""))); + } else { + searchTerms += term.split(QLatin1Char(' ')); + } + index = nextIndex; + } + searchTerms.removeDuplicates(); + + int count = qMin(75, hitList.count()); + QMap<int, QHelpSearchEngine::SearchHit> hitMap; + for (int i = 0; i < count; ++i) { + const QHelpSearchEngine::SearchHit &hit = hitList.at(i); + QString data = QString::fromUtf8(engine.fileData(hit.first)); + + int counter = 0; + foreach (const QString& term, searchTerms) + counter += data.count(term, Qt::CaseInsensitive); + hitMap.insertMulti(counter, hit); + } + + QList<QHelpSearchEngine::SearchHit> boostedList; + QMap<int, QHelpSearchEngine::SearchHit>::const_iterator i; + for (i = hitMap.constEnd(), --i; i != hitMap.constBegin(); --i) + boostedList.append(i.value()); + boostedList += hitList.mid(count - 1, hitList.count()); + + hitList = boostedList; + } +} + + } // namespace clucene + } // namespace fulltextsearch +} // namespace qt + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpsearchindexreader_clucene_p.h b/tools/assistant/lib/qhelpsearchindexreader_clucene_p.h new file mode 100644 index 0000000..892c4e6 --- /dev/null +++ b/tools/assistant/lib/qhelpsearchindexreader_clucene_p.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHINDEXREADERCLUCENE_H +#define QHELPSEARCHINDEXREADERCLUCENE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhelpsearchengine.h" +#include "fulltextsearch/qquery_p.h" + +#include <QtCore/QList> +#include <QtCore/QMutex> +#include <QtCore/QObject> +#include <QtCore/QString> +#include <QtCore/QThread> +#include <QtCore/QWaitCondition> + +class QHelpEngineCore; + +QT_BEGIN_NAMESPACE + +namespace qt { + namespace fulltextsearch { + namespace clucene { + +class QHelpSearchIndexReader : public QThread +{ + Q_OBJECT + +public: + QHelpSearchIndexReader(); + ~QHelpSearchIndexReader(); + + void cancelSearching(); + void search(const QString &collectionFile, + const QString &indexFilesFolder, + const QList<QHelpSearchQuery> &queryList); + + int hitsCount() const; + QHelpSearchEngine::SearchHit hit(int index) const; + +signals: + void searchingStarted(); + void searchingFinished(int hits); + +private: + void run(); + bool defaultQuery(const QString &term, + QCLuceneBooleanQuery &booleanQuery); + bool buildQuery(QCLuceneBooleanQuery &booleanQuery, + const QList<QHelpSearchQuery> &queryList); + void boostSearchHits(const QHelpEngineCore &engine, + QList<QHelpSearchEngine::SearchHit> &hitList, + const QList<QHelpSearchQuery> &queryList); + +private: + QMutex mutex; + QList<QHelpSearchEngine::SearchHit> hitList; + QWaitCondition waitCondition; + + bool m_cancel; + QString m_collectionFile; + QList<QHelpSearchQuery> m_query; + QString m_indexFilesFolder; +}; + + } // namespace clucene + } // namespace fulltextsearch +} // namespace qt + +QT_END_NAMESPACE + +#endif // QHELPSEARCHINDEXREADERCLUCENE_H diff --git a/tools/assistant/lib/qhelpsearchindexreader_default.cpp b/tools/assistant/lib/qhelpsearchindexreader_default.cpp new file mode 100644 index 0000000..617d0d2 --- /dev/null +++ b/tools/assistant/lib/qhelpsearchindexreader_default.cpp @@ -0,0 +1,653 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpenginecore.h" +#include "qhelpsearchindexreader_default_p.h" + +#include <QtCore/QDir> +#include <QtCore/QUrl> +#include <QtCore/QFile> +#include <QtCore/QVariant> +#include <QtCore/QFileInfo> +#include <QtCore/QDataStream> +#include <QtCore/QTextStream> + +QT_BEGIN_NAMESPACE + +namespace qt { + namespace fulltextsearch { + namespace std { + +namespace { + QStringList split( const QString &str ) + { + QStringList lst; + int j = 0; + int i = str.indexOf(QLatin1Char('*'), j ); + + if (str.startsWith(QLatin1String("*"))) + lst << QLatin1String("*"); + + while ( i != -1 ) { + if ( i > j && i <= (int)str.length() ) { + lst << str.mid( j, i - j ); + lst << QLatin1String("*"); + } + j = i + 1; + i = str.indexOf(QLatin1Char('*'), j ); + } + + int l = str.length() - 1; + if ( str.mid( j, l - j + 1 ).length() > 0 ) + lst << str.mid( j, l - j + 1 ); + + return lst; + } +} + + +Reader::Reader() + : indexPath(QString()) + , indexFile(QString()) + , documentFile(QString()) +{ + termList.clear(); + indexTable.clear(); + searchIndexTable.clear(); +} + +Reader::~Reader() +{ + reset(); + searchIndexTable.clear(); +} + +bool Reader::readIndex() +{ + if (indexTable.contains(indexFile)) + return true; + + QFile idxFile(indexFile); + if (!idxFile.open(QFile::ReadOnly)) + return false; + + QString key; + int numOfDocs; + EntryTable entryTable; + QVector<Document> docs; + QDataStream dictStream(&idxFile); + while (!dictStream.atEnd()) { + dictStream >> key; + dictStream >> numOfDocs; + docs.resize(numOfDocs); + dictStream >> docs; + entryTable.insert(key, new Entry(docs)); + } + idxFile.close(); + + if (entryTable.isEmpty()) + return false; + + QFile docFile(documentFile); + if (!docFile.open(QFile::ReadOnly)) + return false; + + QString title, url; + DocumentList documentList; + QDataStream docStream(&docFile); + while (!docStream.atEnd()) { + docStream >> title; + docStream >> url; + documentList.append(QStringList(title) << url); + } + docFile.close(); + + if (documentList.isEmpty()) { + cleanupIndex(entryTable); + return false; + } + + indexTable.insert(indexFile, Index(entryTable, documentList)); + return true; +} + +bool Reader::initCheck() const +{ + return !searchIndexTable.isEmpty(); +} + +void Reader::setIndexPath(const QString &path) +{ + indexPath = path; +} + +void Reader::filterFilesForAttributes(const QStringList &attributes) +{ + searchIndexTable.clear(); + for(IndexTable::ConstIterator it = indexTable.begin(); it != indexTable.end(); ++it) { + const QString fileName = it.key(); + bool containsAll = true; + QStringList split = fileName.split(QLatin1String("@")); + foreach (const QString attribute, attributes) { + if (!split.contains(attribute, Qt::CaseInsensitive)) { + containsAll = false; + break; + } + } + + if (containsAll) + searchIndexTable.insert(fileName, it.value()); + } +} + +void Reader::setIndexFile(const QString &namespaceName, const QString &attributes) +{ + QString extention = namespaceName + QLatin1String("@") + attributes; + indexFile = indexPath + QLatin1String("/indexdb40.") + extention; + documentFile = indexPath + QLatin1String("/indexdoc40.") + extention; +} + +bool Reader::splitSearchTerm(const QString &searchTerm, QStringList *terms, + QStringList *termSeq, QStringList *seqWords) +{ + QString term = searchTerm; + + term = term.simplified(); + term = term.replace(QLatin1String("\'"), QLatin1String("\"")); + term = term.replace(QLatin1String("`"), QLatin1String("\"")); + term = term.replace(QLatin1String("-"), QLatin1String(" ")); + term = term.replace(QRegExp(QLatin1String("\\s[\\S]?\\s")), QLatin1String(" ")); + + *terms = term.split(QLatin1Char(' ')); + QStringList::iterator it = terms->begin(); + for (; it != terms->end(); ++it) { + (*it) = (*it).simplified(); + (*it) = (*it).toLower(); + (*it) = (*it).replace(QLatin1String("\""), QLatin1String("")); + } + + if (term.contains(QLatin1Char('\"'))) { + if ((term.count(QLatin1Char('\"')))%2 == 0) { + int beg = 0; + int end = 0; + QString s; + beg = term.indexOf(QLatin1Char('\"'), beg); + while (beg != -1) { + beg++; + end = term.indexOf(QLatin1Char('\"'), beg); + s = term.mid(beg, end - beg); + s = s.toLower(); + s = s.simplified(); + if (s.contains(QLatin1Char('*'))) { + qWarning("Full Text Search, using a wildcard within phrases is not allowed."); + return false; + } + *seqWords += s.split(QLatin1Char(' ')); + *termSeq << s; + beg = term.indexOf(QLatin1Char('\"'), end + 1); + } + } else { + qWarning("Full Text Search, the closing quotation mark is missing."); + return false; + } + } + + return true; +} + +void Reader::searchInIndex(const QStringList &terms) +{ + foreach (const QString term, terms) { + QVector<Document> documents; + + for(IndexTable::ConstIterator it = searchIndexTable.begin(); + it != searchIndexTable.end(); ++it) { + EntryTable entryTable = it.value().first; + DocumentList documentList = it.value().second; + + if (term.contains(QLatin1Char('*'))) + documents = setupDummyTerm(getWildcardTerms(term, entryTable), entryTable); + else if (entryTable.value(term)) + documents = entryTable.value(term)->documents; + else + continue; + + if (!documents.isEmpty()) { + DocumentInfo info; + QString title, url; + QVector<DocumentInfo> documentsInfo; + foreach(const Document doc, documents) { + info.docNumber = doc.docNumber; + info.frequency = doc.frequency; + info.documentUrl = documentList.at(doc.docNumber).at(1); + info.documentTitle = documentList.at(doc.docNumber).at(0); + documentsInfo.append(info); + } + + bool found = false; + for(QList<TermInfo>::Iterator tit = termList.begin(); + tit != termList.end(); ++tit) { + TermInfo *t = &(*tit); + if(t->term == term) { + t->documents += documentsInfo; + t->frequency += documentsInfo.count(); + found = true; break; + } + } + if (!found) + termList.append(TermInfo(term, documentsInfo.count(), documentsInfo)); + } + } + } + qSort(termList); +} + +QVector<DocumentInfo> Reader::hits() +{ + QVector<DocumentInfo> documents; + if (!termList.count()) + return documents; + + documents = termList.takeFirst().documents; + for(QList<TermInfo>::Iterator it = termList.begin(); it != termList.end(); ++it) { + TermInfo *t = &(*it); + QVector<DocumentInfo> docs = t->documents; + for(QVector<DocumentInfo>::Iterator minDoc_it = documents.begin(); + minDoc_it != documents.end(); ) { + bool found = false; + for (QVector<DocumentInfo>::ConstIterator doc_it = docs.constBegin(); + doc_it != docs.constEnd(); ++doc_it ) { + if ( (*minDoc_it).docNumber == (*doc_it).docNumber ) { + (*minDoc_it).frequency += (*doc_it).frequency; + found = true; + break; + } + } + if (!found) + minDoc_it = documents.erase(minDoc_it); + else + ++minDoc_it; + } + } + + qSort(documents); + return documents; +} + +bool Reader::searchForPattern(const QStringList &patterns, const QStringList &words, + const QByteArray &data) +{ + if (data.isEmpty()) + return false; + + for(QHash<QString, PosEntry*>::ConstIterator mit = + miniIndex.begin(); mit != miniIndex.end(); ++mit) { + delete mit.value(); + } + miniIndex.clear(); + + wordNum = 3; + QStringList::ConstIterator cIt = words.begin(); + for ( ; cIt != words.end(); ++cIt ) + miniIndex.insert(*cIt, new PosEntry(0)); + + QTextStream s(data); + QString text = s.readAll(); + bool valid = true; + const QChar *buf = text.unicode(); + QChar str[64]; + QChar c = buf[0]; + int j = 0; + int i = 0; + while ( j < text.length() ) { + if ( c == QLatin1Char('<') || c == QLatin1Char('&') ) { + valid = false; + if ( i > 1 ) + buildMiniIndex( QString(str,i) ); + i = 0; + c = buf[++j]; + continue; + } + if ( ( c == QLatin1Char('>') || c == QLatin1Char(';') ) && !valid ) { + valid = true; + c = buf[++j]; + continue; + } + if ( !valid ) { + c = buf[++j]; + continue; + } + if ( ( c.isLetterOrNumber() || c == QLatin1Char('_') ) && i < 63 ) { + str[i] = c.toLower(); + ++i; + } else { + if ( i > 1 ) + buildMiniIndex( QString(str,i) ); + i = 0; + } + c = buf[++j]; + } + if ( i > 1 ) + buildMiniIndex( QString(str,i) ); + + QStringList::ConstIterator patIt = patterns.begin(); + QStringList wordLst; + QList<uint> a, b; + QList<uint>::iterator aIt; + for ( ; patIt != patterns.end(); ++patIt ) { + wordLst = (*patIt).split(QLatin1Char(' ')); + a = miniIndex[ wordLst[0] ]->positions; + for ( int j = 1; j < (int)wordLst.count(); ++j ) { + b = miniIndex[ wordLst[j] ]->positions; + aIt = a.begin(); + while ( aIt != a.end() ) { + if ( b.contains( *aIt + 1 )) { + (*aIt)++; + ++aIt; + } else { + aIt = a.erase( aIt ); + } + } + } + } + if ( a.count() ) + return true; + return false; +} + +QVector<Document> Reader::setupDummyTerm(const QStringList &terms, + const EntryTable &entryTable) +{ + QList<Term> termList; + for (QStringList::ConstIterator it = terms.begin(); it != terms.end(); ++it) { + if (entryTable.value(*it)) { + Entry *e = entryTable.value(*it); + termList.append(Term(*it, e->documents.count(), e->documents ) ); + } + } + QVector<Document> maxList(0); + if ( !termList.count() ) + return maxList; + qSort(termList); + + maxList = termList.takeLast().documents; + for(QList<Term>::Iterator it = termList.begin(); it != termList.end(); ++it) { + Term *t = &(*it); + QVector<Document> docs = t->documents; + for (QVector<Document>::iterator docIt = docs.begin(); docIt != docs.end(); ++docIt ) { + if ( maxList.indexOf( *docIt ) == -1 ) + maxList.append( *docIt ); + } + } + return maxList; +} + +QStringList Reader::getWildcardTerms(const QString &term, + const EntryTable &entryTable) +{ + QStringList lst; + QStringList terms = split(term); + QStringList::Iterator iter; + + for(EntryTable::ConstIterator it = entryTable.begin(); + it != entryTable.end(); ++it) { + int index = 0; + bool found = false; + QString text( it.key() ); + for ( iter = terms.begin(); iter != terms.end(); ++iter ) { + if ( *iter == QLatin1String("*") ) { + found = true; + continue; + } + if ( iter == terms.begin() && (*iter)[0] != text[0] ) { + found = false; + break; + } + index = text.indexOf( *iter, index ); + if ( *iter == terms.last() && index != (int)text.length()-1 ) { + index = text.lastIndexOf( *iter ); + if ( index != (int)text.length() - (int)(*iter).length() ) { + found = false; + break; + } + } + if ( index != -1 ) { + found = true; + index += (*iter).length(); + continue; + } else { + found = false; + break; + } + } + if (found) + lst << text; + } + + return lst; +} + +void Reader::buildMiniIndex(const QString &string) +{ + if (miniIndex[string]) + miniIndex[string]->positions.append(wordNum); + ++wordNum; +} + +void Reader::reset() +{ + for(IndexTable::Iterator it = indexTable.begin(); + it != indexTable.end(); ++it) { + cleanupIndex(it.value().first); + it.value().second.clear(); + } +} + +void Reader::cleanupIndex(EntryTable &entryTable) +{ + for(EntryTable::ConstIterator it = + entryTable.begin(); it != entryTable.end(); ++it) { + delete it.value(); + } + + entryTable.clear(); +} + + +QHelpSearchIndexReader::QHelpSearchIndexReader() + : QThread() + , m_cancel(false) +{ + // nothing todo +} + +QHelpSearchIndexReader::~QHelpSearchIndexReader() +{ + mutex.lock(); + this->m_cancel = true; + waitCondition.wakeOne(); + mutex.unlock(); + + wait(); +} + +void QHelpSearchIndexReader::cancelSearching() +{ + mutex.lock(); + this->m_cancel = true; + mutex.unlock(); +} + +void QHelpSearchIndexReader::search(const QString &collectionFile, + const QString &indexFilesFolder, + const QList<QHelpSearchQuery> &queryList) +{ + QMutexLocker lock(&mutex); + + this->hitList.clear(); + this->m_cancel = false; + this->m_query = queryList; + this->m_collectionFile = collectionFile; + this->m_indexFilesFolder = indexFilesFolder; + + start(QThread::NormalPriority); +} + +int QHelpSearchIndexReader::hitsCount() const +{ + return hitList.count(); +} + +QHelpSearchEngine::SearchHit QHelpSearchIndexReader::hit(int index) const +{ + return hitList.at(index); +} + +void QHelpSearchIndexReader::run() +{ + mutex.lock(); + + if (m_cancel) { + mutex.unlock(); + return; + } + + const QList<QHelpSearchQuery> &queryList = this->m_query; + const QLatin1String key("DefaultSearchNamespaces"); + const QString collectionFile(this->m_collectionFile); + const QString indexPath = m_indexFilesFolder; + + mutex.unlock(); + + QString queryTerm; + foreach (const QHelpSearchQuery query, queryList) { + if (query.fieldName == QHelpSearchQuery::DEFAULT) { + queryTerm = query.wordList.at(0); + break; + } + } + + if (queryTerm.isEmpty()) + return; + + QHelpEngineCore engine(collectionFile, 0); + if (!engine.setupData()) + return; + + const QStringList registeredDocs = engine.registeredDocumentations(); + const QStringList indexedNamespaces = engine.customValue(key).toString(). + split(QLatin1String("|"), QString::SkipEmptyParts); + + emit searchingStarted(); + + // setup the reader + m_reader.setIndexPath(indexPath); + foreach(const QString namespaceName, registeredDocs) { + mutex.lock(); + if (m_cancel) { + mutex.unlock(); + searchingFinished(0); // TODO: check this ??? + return; + } + mutex.unlock(); + + const QList<QStringList> attributeSets = + engine.filterAttributeSets(namespaceName); + + foreach (QStringList attributes, attributeSets) { + // read all index files + m_reader.setIndexFile(namespaceName, attributes.join(QLatin1String("@"))); + if (!m_reader.readIndex()) { + qWarning("Full Text Search, could not read file for namespace: %s.", + namespaceName.toUtf8().constData()); + } + } + } + + // get the current filter attributes and minimize the index files table + m_reader.filterFilesForAttributes(engine.filterAttributes(engine.currentFilter())); + + hitList.clear(); + QStringList terms, termSeq, seqWords; + if (m_reader.initCheck() && // check if we could read anything + m_reader.splitSearchTerm(queryTerm, &terms, &termSeq, &seqWords) ) { + + // search for term(s) + m_reader.searchInIndex(terms); // TODO: should this be interruptible as well ??? + + QVector<DocumentInfo> hits = m_reader.hits(); + if (!hits.isEmpty()) { + if (termSeq.isEmpty()) { + foreach (const DocumentInfo docInfo, hits) { + mutex.lock(); + if (m_cancel) { + mutex.unlock(); + searchingFinished(0); // TODO: check this, speed issue while locking??? + return; + } + mutex.unlock(); + hitList.append(qMakePair(docInfo.documentTitle, docInfo.documentUrl)); + } + } else { + foreach (const DocumentInfo docInfo, hits) { + mutex.lock(); + if (m_cancel) { + mutex.unlock(); + searchingFinished(0); // TODO: check this, speed issue while locking??? + return; + } + mutex.unlock(); + + if (m_reader.searchForPattern(termSeq, seqWords, engine.fileData(docInfo.documentUrl))) // TODO: should this be interruptible as well ??? + hitList.append(qMakePair(docInfo.documentTitle, docInfo.documentUrl)); + } + } + } + } + + emit searchingFinished(hitList.count()); +} + + } // namespace std + } // namespace fulltextsearch +} // namespace qt + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpsearchindexreader_default_p.h b/tools/assistant/lib/qhelpsearchindexreader_default_p.h new file mode 100644 index 0000000..22480f7 --- /dev/null +++ b/tools/assistant/lib/qhelpsearchindexreader_default_p.h @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHINDEXREADERDEFAULT_H +#define QHELPSEARCHINDEXREADERDEFAULT_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhelpsearchindex_default_p.h" +#include "qhelpsearchengine.h" + +#include <QtCore/QHash> +#include <QtCore/QPair> +#include <QtCore/QList> +#include <QtCore/QMutex> +#include <QtCore/QString> +#include <QtCore/QThread> +#include <QtCore/QObject> +#include <QtCore/QVector> +#include <QtCore/QByteArray> +#include <QtCore/QStringList> +#include <QtCore/QWaitCondition> + +QT_BEGIN_NAMESPACE + +struct Entry; +struct PosEntry; + +namespace qt { + namespace fulltextsearch { + namespace std { + +class Reader +{ + typedef QList<QStringList> DocumentList; + typedef QHash<QString, Entry*> EntryTable; + typedef QPair<EntryTable, DocumentList> Index; + typedef QHash<QString, Index> IndexTable; + +public: + Reader(); + ~Reader(); + + bool readIndex(); + bool initCheck() const; + void setIndexPath(const QString &path); + void filterFilesForAttributes(const QStringList &attributes); + void setIndexFile(const QString &namespaceName, const QString &attributes); + bool splitSearchTerm(const QString &searchTerm, QStringList *terms, + QStringList *termSeq, QStringList *seqWords); + + void searchInIndex(const QStringList &terms); + QVector<DocumentInfo> hits(); + bool searchForPattern(const QStringList &patterns, + const QStringList &words, const QByteArray &data); + +private: + QVector<Document> setupDummyTerm(const QStringList &terms, const EntryTable &entryTable); + QStringList getWildcardTerms(const QString &term, const EntryTable &entryTable); + void buildMiniIndex(const QString &string); + void reset(); + void cleanupIndex(EntryTable &entryTable); + +private: + uint wordNum; + QString indexPath; + QString indexFile; + QString documentFile; + + IndexTable indexTable; + QList<TermInfo> termList; + IndexTable searchIndexTable; + QHash<QString, PosEntry*> miniIndex; +}; + + +class QHelpSearchIndexReader : public QThread +{ + Q_OBJECT + +public: + QHelpSearchIndexReader(); + ~QHelpSearchIndexReader(); + + void cancelSearching(); + void search(const QString &collectionFile, + const QString &indexFilesFolder, + const QList<QHelpSearchQuery> &queryList); + + int hitsCount() const; + QHelpSearchEngine::SearchHit hit(int index) const; + +signals: + void searchingStarted(); + void searchingFinished(int hits); + +private: + void run(); + +private: + QMutex mutex; + Reader m_reader; + QWaitCondition waitCondition; + QList<QHelpSearchEngine::SearchHit> hitList; + + bool m_cancel; + QList<QHelpSearchQuery> m_query; + QString m_collectionFile; + QString m_indexFilesFolder; +}; + + } // namespace std + } // namespace fulltextsearch +} // namespace qt + +QT_END_NAMESPACE + +#endif // QHELPSEARCHINDEXREADERDEFAULT_H diff --git a/tools/assistant/lib/qhelpsearchindexwriter_clucene.cpp b/tools/assistant/lib/qhelpsearchindexwriter_clucene.cpp new file mode 100644 index 0000000..e53bbae --- /dev/null +++ b/tools/assistant/lib/qhelpsearchindexwriter_clucene.cpp @@ -0,0 +1,481 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpenginecore.h" +#include "qhelp_global.h" +#include "fulltextsearch/qhits_p.h" +#include "fulltextsearch/qquery_p.h" +#include "fulltextsearch/qanalyzer_p.h" +#include "fulltextsearch/qdocument_p.h" +#include "fulltextsearch/qsearchable_p.h" +#include "fulltextsearch/qindexreader_p.h" +#include "fulltextsearch/qindexwriter_p.h" +#include "qhelpsearchindexwriter_clucene_p.h" + +#include <QtCore/QDir> +#include <QtCore/QString> +#include <QtCore/QFileInfo> +#include <QtCore/QTextCodec> +#include <QtCore/QTextStream> + +#include <QtNetwork/QLocalSocket> +#include <QtNetwork/QLocalServer> + +QT_BEGIN_NAMESPACE + +namespace qt { + namespace fulltextsearch { + namespace clucene { + +class DocumentHelper +{ +public: + DocumentHelper(const QString& fileName, const QByteArray &data) + : fileName(fileName) , data(readData(data)) {} + ~DocumentHelper() {} + + bool addFieldsToDocument(QCLuceneDocument *document, + const QString &namespaceName, const QString &attributes = QString()) + { + if (!document) + return false; + + if(!data.isEmpty()) { + QString parsedData = parseData(); + QString parsedTitle = QHelpGlobal::documentTitle(data); + + if(!parsedData.isEmpty()) { + document->add(new QCLuceneField(QLatin1String("content"), + parsedData,QCLuceneField::INDEX_TOKENIZED)); + document->add(new QCLuceneField(QLatin1String("path"), fileName, + QCLuceneField::STORE_YES | QCLuceneField::INDEX_UNTOKENIZED)); + document->add(new QCLuceneField(QLatin1String("title"), parsedTitle, + QCLuceneField::STORE_YES | QCLuceneField::INDEX_UNTOKENIZED)); + document->add(new QCLuceneField(QLatin1String("titleTokenized"), parsedTitle, + QCLuceneField::STORE_YES | QCLuceneField::INDEX_TOKENIZED)); + document->add(new QCLuceneField(QLatin1String("namespace"), namespaceName, + QCLuceneField::STORE_YES | QCLuceneField::INDEX_UNTOKENIZED)); + document->add(new QCLuceneField(QLatin1String("attribute"), attributes, + QCLuceneField::STORE_YES | QCLuceneField::INDEX_TOKENIZED)); + return true; + } + } + + return false; + } + +private: + QString readData(const QByteArray &data) + { + QTextStream textStream(data); + QByteArray charSet = QHelpGlobal::charsetFromData(data).toLatin1(); + textStream.setCodec(QTextCodec::codecForName(charSet.constData())); + + QString stream = textStream.readAll(); + if (stream.isNull() || stream.isEmpty()) + return QString(); + + return stream; + } + + QString parseData() const + { + const int length = data.length(); + const QChar *buf = data.unicode(); + + QString parsedContent; + parsedContent.reserve(length); + + bool valid = true; + int j = 0, count = 0; + + QChar c; + while (j < length) { + c = buf[j++]; + if (c == QLatin1Char('<') || c == QLatin1Char('&')) { + if (count > 1) + parsedContent.append(QLatin1Char(' ')); + count = 0; + valid = false; + continue; + } + if ((c == QLatin1Char('>') || c == QLatin1Char(';')) && !valid) { + valid = true; + continue; + } + if (!valid) + continue; + + if (c.isLetterOrNumber() || c.isPrint()) { + ++count; + parsedContent.append(c.toLower()); + } else { + if (count > 1) + parsedContent.append(QLatin1Char(' ')); + count = 0; + } + } + + return parsedContent; + } + +private: + QString fileName; + QString data; +}; + + +QHelpSearchIndexWriter::QHelpSearchIndexWriter() + : QThread(0) + , m_cancel(false) +{ + // nothing todo +} + +QHelpSearchIndexWriter::~QHelpSearchIndexWriter() +{ + mutex.lock(); + this->m_cancel = true; + waitCondition.wakeOne(); + mutex.unlock(); + + wait(); +} + +void QHelpSearchIndexWriter::cancelIndexing() +{ + mutex.lock(); + this->m_cancel = true; + mutex.unlock(); +} + +void QHelpSearchIndexWriter::updateIndex(const QString &collectionFile, + const QString &indexFilesFolder, bool reindex) +{ + mutex.lock(); + this->m_cancel = false; + this->m_reindex = reindex; + this->m_collectionFile = collectionFile; + this->m_indexFilesFolder = indexFilesFolder; + mutex.unlock(); + + start(QThread::NormalPriority); +} + +void QHelpSearchIndexWriter::optimizeIndex() +{ + if (QCLuceneIndexReader::indexExists(m_indexFilesFolder)) { + if (QCLuceneIndexReader::isLocked(m_indexFilesFolder)) + return; + + QCLuceneStandardAnalyzer analyzer; + QCLuceneIndexWriter writer(m_indexFilesFolder, analyzer, false); + writer.optimize(); + writer.close(); + } +} + +void QHelpSearchIndexWriter::run() +{ + QMutexLocker mutexLocker(&mutex); + + if (m_cancel) + return; + + const bool reindex = this->m_reindex; + const QString collectionFile(this->m_collectionFile); + + mutexLocker.unlock(); + + QHelpEngineCore engine(collectionFile, 0); + if (!engine.setupData()) + return; + + const QLatin1String key("CluceneIndexedNamespaces"); + if (reindex) + engine.setCustomValue(key, QLatin1String("")); + + QMap<QString, QDateTime> indexMap; + const QLatin1String oldKey("CluceneSearchNamespaces"); + if (!engine.customValue(oldKey, QString()).isNull()) { + // old style qhc file < 4.4.2, need to convert... + const QStringList indexedNamespaces = engine.customValue(oldKey). + toString().split(QLatin1String("|"), QString::SkipEmptyParts); + foreach (const QString& nameSpace, indexedNamespaces) + indexMap.insert(nameSpace, QDateTime()); + engine.removeCustomValue(oldKey); + } else { + QDataStream dataStream(engine.customValue(key).toByteArray()); + dataStream >> indexMap; + } + + QString indexPath = m_indexFilesFolder; + + QFileInfo fInfo(indexPath); + if (fInfo.exists() && !fInfo.isWritable()) { + qWarning("Full Text Search, could not create index (missing permissions)."); + return; + } + + emit indexingStarted(); + + QCLuceneIndexWriter *writer = 0; + QCLuceneStandardAnalyzer analyzer; + const QStringList registeredDocs = engine.registeredDocumentations(); + + QLocalSocket localSocket; + localSocket.connectToServer(QString(QLatin1String("QtAssistant%1")) + .arg(QLatin1String(QT_VERSION_STR))); + + QLocalServer localServer; + bool otherInstancesRunning = true; + if (!localSocket.waitForConnected()) { + otherInstancesRunning = false; + localServer.listen(QString(QLatin1String("QtAssistant%1")) + .arg(QLatin1String(QT_VERSION_STR))); + } + +#if !defined(QT_NO_EXCEPTIONS) + try { +#endif + // check if it's locked, and if the other instance is running + if (!otherInstancesRunning && QCLuceneIndexReader::isLocked(indexPath)) + QCLuceneIndexReader::unlock(indexPath); + + if (QCLuceneIndexReader::isLocked(indexPath)) { + // poll unless indexing finished to fake progress + while (QCLuceneIndexReader::isLocked(indexPath)) { + mutexLocker.relock(); + if (m_cancel) + break; + mutexLocker.unlock(); + this->sleep(1); + } + emit indexingFinished(); + return; + } + + if (QCLuceneIndexReader::indexExists(indexPath) && !reindex) { + foreach(const QString& namespaceName, registeredDocs) { + mutexLocker.relock(); + if (m_cancel) { + emit indexingFinished(); + return; + } + mutexLocker.unlock(); + + if (!indexMap.contains(namespaceName)) { + // make sure we remove some partly indexed stuff + removeDocuments(indexPath, namespaceName); + } else { + QString path = engine.documentationFileName(namespaceName); + if (indexMap.value(namespaceName) < QFileInfo(path).lastModified()) { + // make sure we remove some outdated indexed stuff + indexMap.remove(namespaceName); + removeDocuments(indexPath, namespaceName); + } + + if (indexMap.contains(namespaceName)) { + // make sure we really have content indexed for namespace + // NOTE: Extra variable just for GCC 3.3.5 + QLatin1String key("namespace"); + QCLuceneTermQuery query(QCLuceneTerm(key, namespaceName)); + QCLuceneIndexSearcher indexSearcher(indexPath); + QCLuceneHits hits = indexSearcher.search(query); + if (hits.length() <= 0) + indexMap.remove(namespaceName); + } + } + } + writer = new QCLuceneIndexWriter(indexPath, analyzer, false); + } else { + indexMap.clear(); + writer = new QCLuceneIndexWriter(indexPath, analyzer, true); + } +#if !defined(QT_NO_EXCEPTIONS) + } catch (...) { + qWarning("Full Text Search, could not create index writer."); + return; + } +#endif + + writer->setMergeFactor(100); + writer->setMinMergeDocs(1000); + writer->setMaxFieldLength(QCLuceneIndexWriter::DEFAULT_MAX_FIELD_LENGTH); + + QStringList namespaces; + foreach(const QString& namespaceName, registeredDocs) { + mutexLocker.relock(); + if (m_cancel) { + writer->close(); + delete writer; + emit indexingFinished(); + return; + } + mutexLocker.unlock(); + + namespaces.append(namespaceName); + if (indexMap.contains(namespaceName)) + continue; + + const QList<QStringList> attributeSets = + engine.filterAttributeSets(namespaceName); + + if (attributeSets.isEmpty()) { + const QList<QUrl> docFiles = indexableFiles(&engine, namespaceName, + QStringList()); + if (!addDocuments(docFiles, engine, QStringList(), namespaceName, + writer, analyzer)) + break; + } else { + bool bail = false; + foreach (const QStringList& attributes, attributeSets) { + const QList<QUrl> docFiles = indexableFiles(&engine, + namespaceName, attributes); + if (!addDocuments(docFiles, engine, attributes, namespaceName, + writer, analyzer)) { + bail = true; + break; + } + } + if (bail) + break; + } + + mutexLocker.relock(); + if (!m_cancel) { + QString path(engine.documentationFileName(namespaceName)); + indexMap.insert(namespaceName, QFileInfo(path).lastModified()); + writeIndexMap(engine, indexMap); + } + mutexLocker.unlock(); + } + + writer->close(); + delete writer; + + mutexLocker.relock(); + if (!m_cancel) { + mutexLocker.unlock(); + + QStringList indexedNamespaces = indexMap.keys(); + foreach(const QString& namespaceName, indexedNamespaces) { + mutexLocker.relock(); + if (m_cancel) + break; + mutexLocker.unlock(); + + if (!namespaces.contains(namespaceName)) { + indexMap.remove(namespaceName); + writeIndexMap(engine, indexMap); + removeDocuments(indexPath, namespaceName); + } + } + } + emit indexingFinished(); +} + +bool QHelpSearchIndexWriter::addDocuments(const QList<QUrl> docFiles, + const QHelpEngineCore &engine, const QStringList &attributes, + const QString &namespaceName, QCLuceneIndexWriter *writer, + QCLuceneAnalyzer &analyzer) +{ + QMutexLocker locker(&mutex); + const QString attrList = attributes.join(QLatin1String(" ")); + + locker.unlock(); + foreach(const QUrl& url, docFiles) { + QCLuceneDocument document; + DocumentHelper helper(url.toString(), engine.fileData(url)); + if (helper.addFieldsToDocument(&document, namespaceName, attrList)) + writer->addDocument(document, analyzer); + + locker.relock(); + if (m_cancel) + return false; + locker.unlock(); + } + + return true; +} + +void QHelpSearchIndexWriter::removeDocuments(const QString &indexPath, + const QString &namespaceName) +{ + if (namespaceName.isEmpty() || QCLuceneIndexReader::isLocked(indexPath)) + return; + + QCLuceneIndexReader reader = QCLuceneIndexReader::open(indexPath); + reader.deleteDocuments(QCLuceneTerm(QLatin1String("namespace"), + namespaceName)); + + reader.close(); +} + +bool QHelpSearchIndexWriter::writeIndexMap(QHelpEngineCore& engine, + const QMap<QString, QDateTime>& indexMap) +{ + QByteArray bArray; + + QDataStream data(&bArray, QIODevice::ReadWrite); + data << indexMap; + + return engine.setCustomValue(QLatin1String("CluceneIndexedNamespaces"), + bArray); +} + +QList<QUrl> QHelpSearchIndexWriter::indexableFiles(QHelpEngineCore *helpEngine, + const QString &namespaceName, const QStringList &attributes) const +{ + QList<QUrl> docFiles = helpEngine->files(namespaceName, attributes, + QLatin1String("html")); + docFiles += helpEngine->files(namespaceName, attributes, QLatin1String("htm")); + docFiles += helpEngine->files(namespaceName, attributes, QLatin1String("txt")); + + return docFiles; +} + + + } // namespace clucene + } // namespace fulltextsearch +} // namespace qt + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpsearchindexwriter_clucene_p.h b/tools/assistant/lib/qhelpsearchindexwriter_clucene_p.h new file mode 100644 index 0000000..55c852b --- /dev/null +++ b/tools/assistant/lib/qhelpsearchindexwriter_clucene_p.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHINDEXWRITERCLUCENE_H +#define QHELPSEARCHINDEXWRITERCLUCENE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhelpenginecore.h" +#include "fulltextsearch/qanalyzer_p.h" + +#include <QtCore/QUrl> +#include <QtCore/QThread> +#include <QtCore/QMutex> +#include <QtCore/QObject> +#include <QtCore/QString> +#include <QtCore/QDateTime> +#include <QtCore/QStringList> +#include <QtCore/QWaitCondition> + +QT_BEGIN_NAMESPACE + +class QCLuceneIndexWriter; + +namespace qt { + namespace fulltextsearch { + namespace clucene { + +class QHelpSearchIndexWriter : public QThread +{ + Q_OBJECT + +public: + QHelpSearchIndexWriter(); + ~QHelpSearchIndexWriter(); + + void cancelIndexing(); + void updateIndex(const QString &collectionFile, + const QString &indexFilesFolder, bool reindex); + void optimizeIndex(); + +signals: + void indexingStarted(); + void indexingFinished(); + +private: + void run(); + + bool addDocuments(const QList<QUrl> docFiles, const QHelpEngineCore &engine, + const QStringList &attributes, const QString &namespaceName, + QCLuceneIndexWriter *writer, QCLuceneAnalyzer &analyzer); + void removeDocuments(const QString &indexPath, const QString &namespaceName); + + bool writeIndexMap(QHelpEngineCore& engine, + const QMap<QString, QDateTime>& indexMap); + + QList<QUrl> indexableFiles(QHelpEngineCore *helpEngine, + const QString &namespaceName, const QStringList &attributes) const; + +private: + QMutex mutex; + QWaitCondition waitCondition; + + bool m_cancel; + bool m_reindex; + QString m_collectionFile; + QString m_indexFilesFolder; +}; + + } // namespace clucene + } // namespace fulltextsearch +} // namespace clucene + +QT_END_NAMESPACE + +#endif // QHELPSEARCHINDEXWRITERCLUCENE_H diff --git a/tools/assistant/lib/qhelpsearchindexwriter_default.cpp b/tools/assistant/lib/qhelpsearchindexwriter_default.cpp new file mode 100644 index 0000000..d55b984 --- /dev/null +++ b/tools/assistant/lib/qhelpsearchindexwriter_default.cpp @@ -0,0 +1,385 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpsearchindexwriter_default_p.h" +#include "qhelp_global.h" +#include "qhelpenginecore.h" + +#include <QtCore/QDir> +#include <QtCore/QSet> +#include <QtCore/QUrl> +#include <QtCore/QFile> +#include <QtCore/QRegExp> +#include <QtCore/QVariant> +#include <QtCore/QFileInfo> +#include <QtCore/QTextCodec> +#include <QtCore/QTextStream> + +QT_BEGIN_NAMESPACE + +namespace qt { + namespace fulltextsearch { + namespace std { + +Writer::Writer(const QString &path) + : indexPath(path) + , indexFile(QString()) + , documentFile(QString()) +{ + // nothing todo +} + +Writer::~Writer() +{ + reset(); +} + +void Writer::reset() +{ + for(QHash<QString, Entry*>::ConstIterator it = + index.begin(); it != index.end(); ++it) { + delete it.value(); + } + + index.clear(); + documentList.clear(); +} + +bool Writer::writeIndex() const +{ + bool status; + QFile idxFile(indexFile); + if (!(status = idxFile.open(QFile::WriteOnly))) + return status; + + QDataStream indexStream(&idxFile); + for(QHash<QString, Entry*>::ConstIterator it = + index.begin(); it != index.end(); ++it) { + indexStream << it.key(); + indexStream << it.value()->documents.count(); + indexStream << it.value()->documents; + } + idxFile.close(); + + QFile docFile(documentFile); + if (!(status = docFile.open(QFile::WriteOnly))) + return status; + + QDataStream docStream(&docFile); + foreach(const QStringList list, documentList) { + docStream << list.at(0); + docStream << list.at(1); + } + docFile.close(); + + return status; +} + +void Writer::removeIndex() const +{ + QFile idxFile(indexFile); + if (idxFile.exists()) + idxFile.remove(); + + QFile docFile(documentFile); + if (docFile.exists()) + docFile.remove(); +} + +void Writer::setIndexFile(const QString &namespaceName, const QString &attributes) +{ + QString extention = namespaceName + QLatin1String("@") + attributes; + indexFile = indexPath + QLatin1String("/indexdb40.") + extention; + documentFile = indexPath + QLatin1String("/indexdoc40.") + extention; +} + +void Writer::insertInIndex(const QString &string, int docNum) +{ + if (string == QLatin1String("amp") || string == QLatin1String("nbsp")) + return; + + Entry *entry = 0; + if (index.count()) + entry = index[string]; + + if (entry) { + if (entry->documents.last().docNumber != docNum) + entry->documents.append(Document(docNum, 1)); + else + entry->documents.last().frequency++; + } else { + index.insert(string, new Entry(docNum)); + } +} + +void Writer::insertInDocumentList(const QString &title, const QString &url) +{ + documentList.append(QStringList(title) << url); +} + + +QHelpSearchIndexWriter::QHelpSearchIndexWriter() + : QThread() + , m_cancel(false) +{ + // nothing todo +} + +QHelpSearchIndexWriter::~QHelpSearchIndexWriter() +{ + mutex.lock(); + this->m_cancel = true; + waitCondition.wakeOne(); + mutex.unlock(); + + wait(); +} + +void QHelpSearchIndexWriter::cancelIndexing() +{ + mutex.lock(); + this->m_cancel = true; + mutex.unlock(); +} + +void QHelpSearchIndexWriter::updateIndex(const QString &collectionFile, + const QString &indexFilesFolder, + bool reindex) +{ + QMutexLocker lock(&mutex); + + this->m_cancel = false; + this->m_reindex = reindex; + this->m_collectionFile = collectionFile; + this->m_indexFilesFolder = indexFilesFolder; + + start(QThread::NormalPriority); +} + +void QHelpSearchIndexWriter::run() +{ + mutex.lock(); + + if (m_cancel) { + mutex.unlock(); + return; + } + + const bool reindex(this->m_reindex); + const QLatin1String key("DefaultSearchNamespaces"); + const QString collectionFile(this->m_collectionFile); + const QString indexPath = m_indexFilesFolder; + + mutex.unlock(); + + QHelpEngineCore engine(collectionFile, 0); + if (!engine.setupData()) + return; + + if (reindex) + engine.setCustomValue(key, QLatin1String("")); + + const QStringList registeredDocs = engine.registeredDocumentations(); + const QStringList indexedNamespaces = engine.customValue(key).toString(). + split(QLatin1String("|"), QString::SkipEmptyParts); + + emit indexingStarted(); + + QStringList namespaces; + Writer writer(indexPath); + foreach(const QString namespaceName, registeredDocs) { + mutex.lock(); + if (m_cancel) { + mutex.unlock(); + return; + } + mutex.unlock(); + + // if indexed, continue + namespaces.append(namespaceName); + if (indexedNamespaces.contains(namespaceName)) + continue; + + const QList<QStringList> attributeSets = + engine.filterAttributeSets(namespaceName); + + foreach (QStringList attributes, attributeSets) { + // cleanup maybe old or unfinished files + writer.setIndexFile(namespaceName, attributes.join(QLatin1String("@"))); + writer.removeIndex(); + + QSet<QString> documentsSet; + const QList<QUrl> docFiles = engine.files(namespaceName, attributes); + foreach(QUrl url, docFiles) { + if (m_cancel) + return; + + // get rid of duplicated files + if (url.hasFragment()) + url.setFragment(QString()); + + QString s = url.toString(); + if (s.endsWith(QLatin1String(".html")) + || s.endsWith(QLatin1String(".htm")) + || s.endsWith(QLatin1String(".txt"))) + documentsSet.insert(s); + } + + int docNum = 0; + const QStringList documentsList(documentsSet.toList()); + foreach(const QString url, documentsList) { + if (m_cancel) + return; + + QByteArray data(engine.fileData(url)); + if (data.isEmpty()) + continue; + + QTextStream s(data); + QString en = QHelpGlobal::charsetFromData(data); + s.setCodec(QTextCodec::codecForName(en.toLatin1().constData())); + + QString text = s.readAll(); + if (text.isNull()) + continue; + + QString title = QHelpGlobal::documentTitle(text); + + int j = 0; + int i = 0; + bool valid = true; + const QChar *buf = text.unicode(); + QChar str[64]; + QChar c = buf[0]; + + while ( j < text.length() ) { + if (m_cancel) + return; + + if ( c == QLatin1Char('<') || c == QLatin1Char('&') ) { + valid = false; + if ( i > 1 ) + writer.insertInIndex(QString(str,i), docNum); + i = 0; + c = buf[++j]; + continue; + } + if ( ( c == QLatin1Char('>') || c == QLatin1Char(';') ) && !valid ) { + valid = true; + c = buf[++j]; + continue; + } + if ( !valid ) { + c = buf[++j]; + continue; + } + if ( ( c.isLetterOrNumber() || c == QLatin1Char('_') ) && i < 63 ) { + str[i] = c.toLower(); + ++i; + } else { + if ( i > 1 ) + writer.insertInIndex(QString(str,i), docNum); + i = 0; + } + c = buf[++j]; + } + if ( i > 1 ) + writer.insertInIndex(QString(str,i), docNum); + + docNum++; + writer.insertInDocumentList(title, url); + } + + if (writer.writeIndex()) { + engine.setCustomValue(key, addNamespace( + engine.customValue(key).toString(), namespaceName)); + } + + writer.reset(); + } + } + + QStringListIterator qsli(indexedNamespaces); + while (qsli.hasNext()) { + const QString namespaceName = qsli.next(); + if (namespaces.contains(namespaceName)) + continue; + + const QList<QStringList> attributeSets = + engine.filterAttributeSets(namespaceName); + + foreach (QStringList attributes, attributeSets) { + writer.setIndexFile(namespaceName, attributes.join(QLatin1String("@"))); + writer.removeIndex(); + } + + engine.setCustomValue(key, removeNamespace( + engine.customValue(key).toString(), namespaceName)); + } + + emit indexingFinished(); +} + +QString QHelpSearchIndexWriter::addNamespace(const QString namespaces, + const QString &namespaceName) +{ + QString value = namespaces; + if (!value.contains(namespaceName)) + value.append(namespaceName).append(QLatin1String("|")); + + return value; +} + +QString QHelpSearchIndexWriter::removeNamespace(const QString namespaces, + const QString &namespaceName) +{ + QString value = namespaces; + if (value.contains(namespaceName)) + value.remove(namespaceName + QLatin1String("|")); + + return value; +} + + } // namespace std + } // namespace fulltextsearch +} // namespace qt + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpsearchindexwriter_default_p.h b/tools/assistant/lib/qhelpsearchindexwriter_default_p.h new file mode 100644 index 0000000..015eb5a --- /dev/null +++ b/tools/assistant/lib/qhelpsearchindexwriter_default_p.h @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHINDEXWRITERDEFAULT_H +#define QHELPSEARCHINDEXWRITERDEFAULT_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhelpsearchindex_default_p.h" + +#include <QtCore/QHash> +#include <QtCore/QMutex> +#include <QtCore/QObject> +#include <QtCore/QString> +#include <QtCore/QThread> +#include <QtCore/QStringList> +#include <QtCore/QWaitCondition> + +QT_BEGIN_NAMESPACE + +namespace qt { + namespace fulltextsearch { + namespace std { + +class Writer +{ +public: + Writer(const QString &path); + ~Writer(); + + void reset(); + bool writeIndex() const; + void removeIndex() const; + void setIndexFile(const QString &namespaceName, const QString &attributes); + void insertInIndex(const QString &string, int docNum); + void insertInDocumentList(const QString &title, const QString &url); + +private: + QString indexPath; + QString indexFile; + QString documentFile; + + QHash<QString, Entry*> index; + QList<QStringList> documentList; +}; + + +class QHelpSearchIndexWriter : public QThread +{ + Q_OBJECT + +public: + QHelpSearchIndexWriter(); + ~QHelpSearchIndexWriter(); + + void cancelIndexing(); + void updateIndex(const QString &collectionFile, + const QString &indexFilesFolder, bool reindex); + +signals: + void indexingStarted(); + void indexingFinished(); + +private: + void run(); + QString addNamespace(const QString namespaces, const QString &namespaceName); + QString removeNamespace(const QString namespaces, const QString &namespaceName); + +private: + QMutex mutex; + QWaitCondition waitCondition; + + bool m_cancel; + bool m_reindex; + QString m_collectionFile; + QString m_indexFilesFolder; +}; + + } // namespace std + } // namespace fulltextsearch +} // namespace qt + +QT_END_NAMESPACE + +#endif // QHELPSEARCHINDEXWRITERDEFAULT_H diff --git a/tools/assistant/lib/qhelpsearchquerywidget.cpp b/tools/assistant/lib/qhelpsearchquerywidget.cpp new file mode 100644 index 0000000..c018ffc --- /dev/null +++ b/tools/assistant/lib/qhelpsearchquerywidget.cpp @@ -0,0 +1,353 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpsearchquerywidget.h" + +#include <QtCore/QDebug> + +#include <QtCore/QObject> +#include <QtCore/QStringList> + +#include <QtGui/QLabel> +#include <QtGui/QLayout> +#include <QtGui/QLineEdit> +#include <QtGui/QFocusEvent> +#include <QtGui/QPushButton> +#include <QtGui/QToolButton> + +QT_BEGIN_NAMESPACE + +class QHelpSearchQueryWidgetPrivate : public QObject +{ + Q_OBJECT + +private: + QHelpSearchQueryWidgetPrivate() + : QObject() + { + searchButton = 0; + advancedSearchWidget = 0; + showHideAdvancedSearchButton = 0; + defaultQuery = 0; + exactQuery = 0; + similarQuery = 0; + withoutQuery = 0; + allQuery = 0; + atLeastQuery = 0; + } + + ~QHelpSearchQueryWidgetPrivate() + { + // nothing todo + } + + QString escapeString(const QString &text) + { + QString retValue = text; + const QString escape(QLatin1String("\\")); + QStringList escapableCharsList; + escapableCharsList << QLatin1String("\\") << QLatin1String("+") + << QLatin1String("-") << QLatin1String("!") << QLatin1String("(") + << QLatin1String(")") << QLatin1String(":") << QLatin1String("^") + << QLatin1String("[") << QLatin1String("]") << QLatin1String("{") + << QLatin1String("}") << QLatin1String("~"); + + // make sure we won't end up with an empty string + foreach (const QString escapeChar, escapableCharsList) { + if (retValue.contains(escapeChar)) + retValue.replace(escapeChar, QLatin1String("")); + } + if (retValue.trimmed().isEmpty()) + return retValue; + + retValue = text; // now realy escape the string... + foreach (const QString escapeChar, escapableCharsList) { + if (retValue.contains(escapeChar)) + retValue.replace(escapeChar, escape + escapeChar); + } + return retValue; + } + + QStringList buildTermList(const QString query) + { + bool s = false; + QString phrase; + QStringList wordList; + QString searchTerm = query; + + for (int i = 0; i < searchTerm.length(); ++i) { + if (searchTerm[i] == QLatin1Char('\"') && !s) { + s = true; + phrase = searchTerm[i]; + continue; + } + if (searchTerm[i] != QLatin1Char('\"') && s) + phrase += searchTerm[i]; + if (searchTerm[i] == QLatin1Char('\"') && s) { + s = false; + phrase += searchTerm[i]; + wordList.append(phrase); + searchTerm.remove(phrase); + } + } + if (s) + searchTerm.replace(phrase, phrase.mid(1)); + + const QRegExp exp(QLatin1String("\\s+")); + wordList += searchTerm.split(exp, QString::SkipEmptyParts); + return wordList; + } + +private slots: + void showHideAdvancedSearch() + { + bool hidden = advancedSearchWidget->isHidden(); + if (hidden) { + advancedSearchWidget->show(); + showHideAdvancedSearchButton->setText((QLatin1String("-"))); + } else { + advancedSearchWidget->hide(); + showHideAdvancedSearchButton->setText((QLatin1String("+"))); + } + + defaultQuery->setEnabled(!hidden); + } + +private: + friend class QHelpSearchQueryWidget; + + QPushButton *searchButton; + QWidget* advancedSearchWidget; + QToolButton *showHideAdvancedSearchButton; + QLineEdit *defaultQuery; + QLineEdit *exactQuery; + QLineEdit *similarQuery; + QLineEdit *withoutQuery; + QLineEdit *allQuery; + QLineEdit *atLeastQuery; +}; + +#include "qhelpsearchquerywidget.moc" + + +/*! + \class QHelpSearchQueryWidget + \since 4.4 + \inmodule QtHelp + \brief The QHelpSearchQueryWidget class provides a simple line edit or + an advanced widget to enable the user to input a search term in a + standardized input mask. +*/ + +/*! + \fn void QHelpSearchQueryWidget::search() + + This signal is emitted when a the user has the search button invoked. + After reciving the signal you can ask the QHelpSearchQueryWidget for the build list + of QHelpSearchQuery's that you may pass to the QHelpSearchEngine's search() function. +*/ + +/*! + Constructs a new search query widget with the given \a parent. +*/ +QHelpSearchQueryWidget::QHelpSearchQueryWidget(QWidget *parent) + : QWidget(parent) +{ + d = new QHelpSearchQueryWidgetPrivate(); + + QVBoxLayout *vLayout = new QVBoxLayout(this); + vLayout->setMargin(0); + + QHBoxLayout* hBoxLayout = new QHBoxLayout(); + QLabel *label = new QLabel(tr("Search for:"), this); + d->defaultQuery = new QLineEdit(this); + d->searchButton = new QPushButton(tr("Search"), this); + hBoxLayout->addWidget(label); + hBoxLayout->addWidget(d->defaultQuery); + hBoxLayout->addWidget(d->searchButton); + + vLayout->addLayout(hBoxLayout); + + connect(d->searchButton, SIGNAL(clicked()), this, SIGNAL(search())); + connect(d->defaultQuery, SIGNAL(returnPressed()), this, SIGNAL(search())); + +#if defined(QT_CLUCENE_SUPPORT) + hBoxLayout = new QHBoxLayout(); + d->showHideAdvancedSearchButton = new QToolButton(this); + d->showHideAdvancedSearchButton->setText(QLatin1String("+")); + d->showHideAdvancedSearchButton->setMinimumSize(25, 20); + + label = new QLabel(tr("Advanced search"), this); + QSizePolicy sizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); + sizePolicy.setHeightForWidth(label->sizePolicy().hasHeightForWidth()); + label->setSizePolicy(sizePolicy); + + QFrame* hLine = new QFrame(this); + hLine->setFrameStyle(QFrame::HLine); + hBoxLayout->addWidget(d->showHideAdvancedSearchButton); + hBoxLayout->addWidget(label); + hBoxLayout->addWidget(hLine); + + vLayout->addLayout(hBoxLayout); + + // setup advanced search layout + d->advancedSearchWidget = new QWidget(this); + QGridLayout *gLayout = new QGridLayout(d->advancedSearchWidget); + gLayout->setMargin(0); + + label = new QLabel(tr("words <B>similar</B> to:"), this); + gLayout->addWidget(label, 0, 0); + d->similarQuery = new QLineEdit(this); + gLayout->addWidget(d->similarQuery, 0, 1); + + label = new QLabel(tr("<B>without</B> the words:"), this); + gLayout->addWidget(label, 1, 0); + d->withoutQuery = new QLineEdit(this); + gLayout->addWidget(d->withoutQuery, 1, 1); + + label = new QLabel(tr("with <B>exact phrase</B>:"), this); + gLayout->addWidget(label, 2, 0); + d->exactQuery = new QLineEdit(this); + gLayout->addWidget(d->exactQuery, 2, 1); + + label = new QLabel(tr("with <B>all</B> of the words:"), this); + gLayout->addWidget(label, 3, 0); + d->allQuery = new QLineEdit(this); + gLayout->addWidget(d->allQuery, 3, 1); + + label = new QLabel(tr("with <B>at least one</B> of the words:"), this); + gLayout->addWidget(label, 4, 0); + d->atLeastQuery = new QLineEdit(this); + gLayout->addWidget(d->atLeastQuery, 4, 1); + + vLayout->addWidget(d->advancedSearchWidget); + d->advancedSearchWidget->hide(); + + connect(d->exactQuery, SIGNAL(returnPressed()), this, SIGNAL(search())); + connect(d->similarQuery, SIGNAL(returnPressed()), this, SIGNAL(search())); + connect(d->withoutQuery, SIGNAL(returnPressed()), this, SIGNAL(search())); + connect(d->allQuery, SIGNAL(returnPressed()), this, SIGNAL(search())); + connect(d->atLeastQuery, SIGNAL(returnPressed()), this, SIGNAL(search())); + connect(d->showHideAdvancedSearchButton, SIGNAL(clicked()), + d, SLOT(showHideAdvancedSearch())); +#endif +} + +/*! + Destroys the search query widget. +*/ +QHelpSearchQueryWidget::~QHelpSearchQueryWidget() +{ + delete d; +} + +/*! + Returns a list of querys to use in combination with the search engines + search(QList<QHelpSearchQuery> &query) function. +*/ +QList<QHelpSearchQuery> QHelpSearchQueryWidget::query() const +{ +#if !defined(QT_CLUCENE_SUPPORT) + QList<QHelpSearchQuery> queryList; + queryList.append(QHelpSearchQuery(QHelpSearchQuery::DEFAULT, + QStringList(d->defaultQuery->text()))); + + return queryList; +#else + QList<QHelpSearchQuery> queryList; + if (d->defaultQuery->isEnabled()) { + queryList.append(QHelpSearchQuery(QHelpSearchQuery::DEFAULT, + d->buildTermList(d->escapeString(d->defaultQuery->text())))); + } else { + const QRegExp exp(QLatin1String("\\s+")); + QStringList lst = d->similarQuery->text().split(exp, QString::SkipEmptyParts); + if (!lst.isEmpty()) { + QStringList fuzzy; + foreach (const QString term, lst) + fuzzy += d->buildTermList(d->escapeString(term)); + queryList.append(QHelpSearchQuery(QHelpSearchQuery::FUZZY, fuzzy)); + } + + lst = d->withoutQuery->text().split(exp, QString::SkipEmptyParts); + if (!lst.isEmpty()) { + QStringList without; + foreach (const QString term, lst) + without.append(d->escapeString(term)); + queryList.append(QHelpSearchQuery(QHelpSearchQuery::WITHOUT, without)); + } + + if (!d->exactQuery->text().isEmpty()) { + QString phrase = d->exactQuery->text().remove(QLatin1Char('\"')); + phrase = d->escapeString(phrase.simplified()); + queryList.append(QHelpSearchQuery(QHelpSearchQuery::PHRASE, QStringList(phrase))); + } + + lst = d->allQuery->text().split(exp, QString::SkipEmptyParts); + if (!lst.isEmpty()) { + QStringList all; + foreach (const QString term, lst) + all.append(d->escapeString(term)); + queryList.append(QHelpSearchQuery(QHelpSearchQuery::ALL, all)); + } + + lst = d->atLeastQuery->text().split(exp, QString::SkipEmptyParts); + if (!lst.isEmpty()) { + QStringList atLeast; + foreach (const QString term, lst) + atLeast += d->buildTermList(d->escapeString(term)); + queryList.append(QHelpSearchQuery(QHelpSearchQuery::ATLEAST, atLeast)); + } + } + return queryList; +#endif +} + +/*! \reimp +*/ +void QHelpSearchQueryWidget::focusInEvent(QFocusEvent *focusEvent) +{ + if (focusEvent->reason() != Qt::MouseFocusReason) { + d->defaultQuery->selectAll(); + d->defaultQuery->setFocus(); + } +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpsearchquerywidget.h b/tools/assistant/lib/qhelpsearchquerywidget.h new file mode 100644 index 0000000..f4bcf3e --- /dev/null +++ b/tools/assistant/lib/qhelpsearchquerywidget.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHQUERYWIDGET_H +#define QHELPSEARCHQUERYWIDGET_H + +#include <QtHelp/qhelp_global.h> +#include <QtHelp/qhelpsearchengine.h> + +#include <QtCore/QMap> +#include <QtCore/QString> +#include <QtCore/QStringList> + +#include <QtGui/QWidget> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Help) + +class QFocusEvent; +class QHelpSearchQueryWidgetPrivate; + +class QHELP_EXPORT QHelpSearchQueryWidget : public QWidget +{ + Q_OBJECT + +public: + QHelpSearchQueryWidget(QWidget *parent = 0); + ~QHelpSearchQueryWidget(); + + QList<QHelpSearchQuery> query() const; + +Q_SIGNALS: + void search(); + +private: + void focusInEvent(QFocusEvent *focusEvent); + +private: + QHelpSearchQueryWidgetPrivate *d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QHELPSEARCHQUERYWIDGET_H diff --git a/tools/assistant/lib/qhelpsearchresultwidget.cpp b/tools/assistant/lib/qhelpsearchresultwidget.cpp new file mode 100644 index 0000000..e72cf97 --- /dev/null +++ b/tools/assistant/lib/qhelpsearchresultwidget.cpp @@ -0,0 +1,439 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpsearchresultwidget.h" + +#include <QtCore/QList> +#include <QtCore/QString> +#include <QtCore/QPointer> +#include <QtCore/QStringList> + +#include <QtGui/QLabel> +#include <QtGui/QLayout> +#include <QtGui/QMouseEvent> +#include <QtGui/QHeaderView> +#include <QtGui/QSpacerItem> +#include <QtGui/QToolButton> +#include <QtGui/QTreeWidget> +#include <QtGui/QTextBrowser> +#include <QtGui/QTreeWidgetItem> + +QT_BEGIN_NAMESPACE + +class QDefaultResultWidget : public QTreeWidget +{ + Q_OBJECT + +public: + QDefaultResultWidget(QWidget *parent = 0) + : QTreeWidget(parent) + { + header()->hide(); + connect(this, SIGNAL(itemActivated(QTreeWidgetItem*, int)), + this, SLOT(itemActivated(QTreeWidgetItem*, int))); + } + + void showResultPage(const QList<QHelpSearchEngine::SearchHit> hits) + { + foreach (const QHelpSearchEngine::SearchHit hit, hits) + new QTreeWidgetItem(this, QStringList(hit.first) << hit.second); + } + +signals: + void requestShowLink(const QUrl &url); + +private slots: + void itemActivated(QTreeWidgetItem *item, int /* column */) + { + if (item) { + QString data = item->data(1, Qt::DisplayRole).toString(); + emit requestShowLink(data); + } + } +}; + + +class QCLuceneResultWidget : public QTextBrowser +{ + Q_OBJECT + +public: + QCLuceneResultWidget(QWidget *parent = 0) + : QTextBrowser(parent) + { + connect(this, SIGNAL(anchorClicked(const QUrl&)), + this, SIGNAL(requestShowLink(const QUrl&))); + setContextMenuPolicy(Qt::NoContextMenu); + } + + void showResultPage(const QList<QHelpSearchEngine::SearchHit> hits, bool isIndexing) + { + QString htmlFile = QString(QLatin1String("<html><head><title>%1</title></head><body>")) + .arg(tr("Search Results")); + + int count = hits.count(); + if (count != 0) { + if (isIndexing) + htmlFile += QString(QLatin1String("<div style=\"text-align:left; font-weight:bold; color:red\">" + "%1 <span style=\"font-weight:normal; color:black\">" + "%2</span></div></div><br>")).arg(tr("Note:")) + .arg(tr("The search results may not be complete since the " + "documentation is still being indexed!")); + + foreach (const QHelpSearchEngine::SearchHit hit, hits) { + htmlFile += QString(QLatin1String("<div style=\"text-align:left; font-weight:bold\"" + "><a href=\"%1\">%2</a><div style=\"color:green; font-weight:normal;" + " margin:5px\">%1</div></div><p></p>")) + .arg(hit.first).arg(hit.second); + } + } else { + htmlFile += QLatin1String("<div align=\"center\"><br><br><h2>") + + tr("Your search did not match any documents.") + + QLatin1String("</h2><div>"); + if (isIndexing) + htmlFile += QLatin1String("<div align=\"center\"><h3>") + + tr("(The reason for this might be that the documentation " + "is still being indexed.)") + + QLatin1String("</h3><div>"); + } + + htmlFile += QLatin1String("</body></html>"); + + setHtml(htmlFile); + } + +signals: + void requestShowLink(const QUrl &url); + +private slots: + void setSource(const QUrl & /* name */) {} +}; + + +class QHelpSearchResultWidgetPrivate : public QObject +{ + Q_OBJECT + +private slots: + void setResults(int hitsCount) + { + if (!searchEngine.isNull()) { +#if defined(QT_CLUCENE_SUPPORT) + showFirstResultPage(); + updateNextButtonState(((hitsCount > 20) ? true : false)); +#else + resultTreeWidget->clear(); + resultTreeWidget->showResultPage(searchEngine->hits(0, hitsCount)); +#endif + } + } + + void showNextResultPage() + { + if (!searchEngine.isNull() + && resultLastToShow < searchEngine->hitsCount()) { + resultLastToShow += 20; + resultFirstToShow += 20; + + resultTextBrowser->showResultPage(searchEngine->hits(resultFirstToShow, + resultLastToShow), isIndexing); + if (resultLastToShow >= searchEngine->hitsCount()) + updateNextButtonState(false); + } + updateHitRange(); + } + + void showLastResultPage() + { + if (!searchEngine.isNull()) { + resultLastToShow = searchEngine->hitsCount(); + resultFirstToShow = resultLastToShow - (resultLastToShow % 20); + + if (resultFirstToShow == resultLastToShow) + resultFirstToShow -= 20; + + resultTextBrowser->showResultPage(searchEngine->hits(resultFirstToShow, + resultLastToShow), isIndexing); + updateNextButtonState(false); + } + updateHitRange(); + } + + void showFirstResultPage() + { + if (!searchEngine.isNull()) { + resultLastToShow = 20; + resultFirstToShow = 0; + + resultTextBrowser->showResultPage(searchEngine->hits(resultFirstToShow, + resultLastToShow), isIndexing); + updatePrevButtonState(false); + } + updateHitRange(); + } + + void showPreviousResultPage() + { + if (!searchEngine.isNull()) { + int count = resultLastToShow % 20; + if (count == 0 || resultLastToShow != searchEngine->hitsCount()) + count = 20; + + resultLastToShow -= count; + resultFirstToShow = resultLastToShow -20; + + resultTextBrowser->showResultPage(searchEngine->hits(resultFirstToShow, + resultLastToShow), isIndexing); + if (resultFirstToShow == 0) + updatePrevButtonState(false); + } + updateHitRange(); + } + + void updatePrevButtonState(bool state = true) + { + firstResultPage->setEnabled(state); + previousResultPage->setEnabled(state); + } + + void updateNextButtonState(bool state = true) + { + nextResultPage->setEnabled(state); + lastResultPage->setEnabled(state); + } + + void indexingStarted() + { + isIndexing = true; + } + + void indexingFinished() + { + isIndexing = false; + } + +private: + QHelpSearchResultWidgetPrivate(QHelpSearchEngine *engine) + : QObject() + , searchEngine(engine) + , isIndexing(false) + { + resultTreeWidget = 0; + resultTextBrowser = 0; + + resultLastToShow = 20; + resultFirstToShow = 0; + + firstResultPage = 0; + previousResultPage = 0; + hitsLabel = 0; + nextResultPage = 0; + lastResultPage = 0; + + connect(searchEngine, SIGNAL(indexingStarted()), + this, SLOT(indexingStarted())); + connect(searchEngine, SIGNAL(indexingFinished()), + this, SLOT(indexingFinished())); + } + + ~QHelpSearchResultWidgetPrivate() + { + delete searchEngine; + } + + QToolButton* setupToolButton(const QString &iconPath) + { + QToolButton *button = new QToolButton(); + button->setEnabled(false); + button->setAutoRaise(true); + button->setIcon(QIcon(iconPath)); + button->setIconSize(QSize(12, 12)); + button->setMaximumSize(QSize(16, 16)); + + return button; + } + + void updateHitRange() + { + int last = 0; + int first = 0; + int count = 0; + + if (!searchEngine.isNull()) { + count = searchEngine->hitsCount(); + if (count > 0) { + first = resultFirstToShow +1; + last = resultLastToShow > count ? count : resultLastToShow; + } + } + hitsLabel->setText(tr("%1 - %2 of %3 Hits").arg(first).arg(last).arg(count)); + } + +private: + friend class QHelpSearchResultWidget; + + QPointer<QHelpSearchEngine> searchEngine; + + QDefaultResultWidget *resultTreeWidget; + QCLuceneResultWidget *resultTextBrowser; + + int resultLastToShow; + int resultFirstToShow; + bool isIndexing; + + QToolButton *firstResultPage; + QToolButton *previousResultPage; + QLabel *hitsLabel; + QToolButton *nextResultPage; + QToolButton *lastResultPage; +}; + +#include "qhelpsearchresultwidget.moc" + + +/*! + \class QHelpSearchResultWidget + \since 4.4 + \inmodule QtHelp + \brief The QHelpSearchResultWidget class provides either a tree + widget or a text browser depending on the used search engine to display + the hits found by the search. +*/ + +/*! + \fn void QHelpSearchResultWidget::requestShowLink(const QUrl &link) + + This signal is emitted when a item is activated and its associated + \a link should be shown. +*/ + +QHelpSearchResultWidget::QHelpSearchResultWidget(QHelpSearchEngine *engine) + : QWidget(0) + , d(new QHelpSearchResultWidgetPrivate(engine)) +{ + QVBoxLayout *vLayout = new QVBoxLayout(this); + vLayout->setMargin(0); + vLayout->setSpacing(0); + +#if defined(QT_CLUCENE_SUPPORT) + QHBoxLayout *hBoxLayout = new QHBoxLayout(); +#ifndef Q_OS_MAC + hBoxLayout->setMargin(0); + hBoxLayout->setSpacing(0); +#endif + hBoxLayout->addWidget(d->firstResultPage = d->setupToolButton( + QString::fromUtf8(":/trolltech/assistant/images/3leftarrow.png"))); + + hBoxLayout->addWidget(d->previousResultPage = d->setupToolButton( + QString::fromUtf8(":/trolltech/assistant/images/1leftarrow.png"))); + + d->hitsLabel = new QLabel(tr("0 - 0 of 0 Hits"), this); + d->hitsLabel->setEnabled(false); + hBoxLayout->addWidget(d->hitsLabel); + d->hitsLabel->setAlignment(Qt::AlignCenter); + d->hitsLabel->setMinimumSize(QSize(150, d->hitsLabel->height())); + + hBoxLayout->addWidget(d->nextResultPage = d->setupToolButton( + QString::fromUtf8(":/trolltech/assistant/images/1rightarrow.png"))); + + hBoxLayout->addWidget(d->lastResultPage = d->setupToolButton( + QString::fromUtf8(":/trolltech/assistant/images/3rightarrow.png"))); + + QSpacerItem *spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + hBoxLayout->addItem(spacer); + + vLayout->addLayout(hBoxLayout); + + d->resultTextBrowser = new QCLuceneResultWidget(this); + vLayout->addWidget(d->resultTextBrowser); + + connect(d->resultTextBrowser, SIGNAL(requestShowLink(const QUrl&)), this, + SIGNAL(requestShowLink(const QUrl&))); + + connect(d->nextResultPage, SIGNAL(clicked()), d, SLOT(showNextResultPage())); + connect(d->lastResultPage, SIGNAL(clicked()), d, SLOT(showLastResultPage())); + connect(d->firstResultPage, SIGNAL(clicked()), d, SLOT(showFirstResultPage())); + connect(d->previousResultPage, SIGNAL(clicked()), d, SLOT(showPreviousResultPage())); + + connect(d->firstResultPage, SIGNAL(clicked()), d, SLOT(updateNextButtonState())); + connect(d->previousResultPage, SIGNAL(clicked()), d, SLOT(updateNextButtonState())); + connect(d->nextResultPage, SIGNAL(clicked()), d, SLOT(updatePrevButtonState())); + connect(d->lastResultPage, SIGNAL(clicked()), d, SLOT(updatePrevButtonState())); + +#else + d->resultTreeWidget = new QDefaultResultWidget(this); + vLayout->addWidget(d->resultTreeWidget); + connect(d->resultTreeWidget, SIGNAL(requestShowLink(const QUrl&)), this, + SIGNAL(requestShowLink(const QUrl&))); +#endif + + connect(engine, SIGNAL(searchingFinished(int)), d, SLOT(setResults(int))); +} + +/*! + Destroys the search result widget. +*/ +QHelpSearchResultWidget::~QHelpSearchResultWidget() +{ + delete d; +} + +/*! + Returns a reference of the URL that the item at \a point owns, or an + empty URL if no item exists at that point. +*/ +QUrl QHelpSearchResultWidget::linkAt(const QPoint &point) +{ + QUrl url; +#if defined(QT_CLUCENE_SUPPORT) + if (d->resultTextBrowser) + url = d->resultTextBrowser->anchorAt(point); +#else + if (d->resultTreeWidget) { + QTreeWidgetItem *item = d->resultTreeWidget->itemAt(point); + if (item) + url = item->data(1, Qt::DisplayRole).toString(); + } +#endif + return url; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpsearchresultwidget.h b/tools/assistant/lib/qhelpsearchresultwidget.h new file mode 100644 index 0000000..26bc1d97 --- /dev/null +++ b/tools/assistant/lib/qhelpsearchresultwidget.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHRESULTWIDGET_H +#define QHELPSEARCHRESULTWIDGET_H + +#include <QtHelp/qhelpsearchengine.h> +#include <QtHelp/qhelp_global.h> + +#include <QtCore/QUrl> +#include <QtCore/QPoint> +#include <QtCore/QObject> + +#include <QtGui/QWidget> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Help) + +class QHelpSearchResultWidgetPrivate; + +class QHELP_EXPORT QHelpSearchResultWidget : public QWidget +{ + Q_OBJECT + +public: + ~QHelpSearchResultWidget(); + QUrl linkAt(const QPoint &point); + +Q_SIGNALS: + void requestShowLink(const QUrl &url); + +private: + friend class QHelpSearchEngine; + + QHelpSearchResultWidgetPrivate *d; + QHelpSearchResultWidget(QHelpSearchEngine *engine); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QHELPSEARCHRESULTWIDGET_H |