summaryrefslogtreecommitdiffstats
path: root/khelpcenter
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit4aed2c8219774f5d797760606b8489a92ddc5163 (patch)
tree3f8c130f7d269626bf6a9447407ef6c35954426a /khelpcenter
downloadtdebase-4aed2c8219774f5d797760606b8489a92ddc5163.tar.gz
tdebase-4aed2c8219774f5d797760606b8489a92ddc5163.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebase@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'khelpcenter')
-rw-r--r--khelpcenter/COPYING339
-rw-r--r--khelpcenter/DESIGN433
-rw-r--r--khelpcenter/Help.desktop86
-rw-r--r--khelpcenter/Makefile.am57
-rw-r--r--khelpcenter/README.htdig14
-rw-r--r--khelpcenter/README.metadata129
-rw-r--r--khelpcenter/application.cpp89
-rw-r--r--khelpcenter/application.h45
-rw-r--r--khelpcenter/configure.in.in2
-rw-r--r--khelpcenter/docentry.cpp348
-rw-r--r--khelpcenter/docentry.h117
-rw-r--r--khelpcenter/docentrytraverser.cpp49
-rw-r--r--khelpcenter/docentrytraverser.h44
-rw-r--r--khelpcenter/docmetainfo.cpp287
-rw-r--r--khelpcenter/docmetainfo.h80
-rw-r--r--khelpcenter/fontdialog.cpp212
-rw-r--r--khelpcenter/fontdialog.h66
-rw-r--r--khelpcenter/formatter.cpp222
-rw-r--r--khelpcenter/formatter.h55
-rw-r--r--khelpcenter/glossary.cpp322
-rw-r--r--khelpcenter/glossary.h146
-rw-r--r--khelpcenter/glossary.html.in95
-rw-r--r--khelpcenter/glossary.xslt34
-rw-r--r--khelpcenter/history.cpp351
-rw-r--r--khelpcenter/history.h107
-rw-r--r--khelpcenter/htmlsearch.cpp61
-rw-r--r--khelpcenter/htmlsearch.h33
-rw-r--r--khelpcenter/htmlsearch/Makefile.am39
-rw-r--r--khelpcenter/htmlsearch/checked.xpm23
-rw-r--r--khelpcenter/htmlsearch/htmlsearch.cpp487
-rw-r--r--khelpcenter/htmlsearch/htmlsearch.desktop239
-rw-r--r--khelpcenter/htmlsearch/htmlsearch.h64
-rw-r--r--khelpcenter/htmlsearch/index.cpp31
-rw-r--r--khelpcenter/htmlsearch/kcmhtmlsearch.cpp370
-rw-r--r--khelpcenter/htmlsearch/kcmhtmlsearch.h81
-rw-r--r--khelpcenter/htmlsearch/klangcombo.cpp52
-rw-r--r--khelpcenter/htmlsearch/klangcombo.h47
-rw-r--r--khelpcenter/htmlsearch/ktagcombobox.cpp252
-rw-r--r--khelpcenter/htmlsearch/ktagcombobox.h92
-rw-r--r--khelpcenter/htmlsearch/long.html6
-rw-r--r--khelpcenter/htmlsearch/meinproc_wrapper4
-rw-r--r--khelpcenter/htmlsearch/nomatch.html21
-rw-r--r--khelpcenter/htmlsearch/progressdialog.cpp76
-rw-r--r--khelpcenter/htmlsearch/progressdialog.h35
-rw-r--r--khelpcenter/htmlsearch/short.html1
-rw-r--r--khelpcenter/htmlsearch/star.pngbin0 -> 690 bytes
-rw-r--r--khelpcenter/htmlsearch/star_blank.pngbin0 -> 151 bytes
-rw-r--r--khelpcenter/htmlsearch/syntax.html19
-rw-r--r--khelpcenter/htmlsearch/unchecked.xpm22
-rw-r--r--khelpcenter/htmlsearch/wrapper.html16
-rw-r--r--khelpcenter/htmlsearchconfig.cpp151
-rw-r--r--khelpcenter/htmlsearchconfig.h58
-rw-r--r--khelpcenter/index.html.in42
-rw-r--r--khelpcenter/infotree.cpp184
-rw-r--r--khelpcenter/infotree.h48
-rw-r--r--khelpcenter/intro.html.in141
-rw-r--r--khelpcenter/kcmhelpcenter.cpp680
-rw-r--r--khelpcenter/kcmhelpcenter.desktop236
-rw-r--r--khelpcenter/kcmhelpcenter.h180
-rw-r--r--khelpcenter/khc_indexbuilder.cpp221
-rw-r--r--khelpcenter/khc_indexbuilder.h61
-rw-r--r--khelpcenter/khelpcenter.desktop133
-rw-r--r--khelpcenter/khelpcenter.kcfg36
-rw-r--r--khelpcenter/khelpcenterui.rc53
-rw-r--r--khelpcenter/mainwindow.cpp467
-rw-r--r--khelpcenter/mainwindow.h108
-rw-r--r--khelpcenter/navigator.cpp672
-rw-r--r--khelpcenter/navigator.h153
-rw-r--r--khelpcenter/navigatorappitem.cpp147
-rw-r--r--khelpcenter/navigatorappitem.h58
-rw-r--r--khelpcenter/navigatoritem.cpp105
-rw-r--r--khelpcenter/navigatoritem.h68
-rw-r--r--khelpcenter/pics/Makefile.am6
-rw-r--r--khelpcenter/pics/hi128-app-khelpcenter.pngbin0 -> 13735 bytes
-rw-r--r--khelpcenter/pics/hi16-app-khelpcenter.pngbin0 -> 1076 bytes
-rw-r--r--khelpcenter/pics/hi22-app-khelpcenter.pngbin0 -> 1533 bytes
-rw-r--r--khelpcenter/pics/hi32-app-khelpcenter.pngbin0 -> 2012 bytes
-rw-r--r--khelpcenter/pics/hi48-app-khelpcenter.pngbin0 -> 4107 bytes
-rw-r--r--khelpcenter/pics/hi64-app-khelpcenter.pngbin0 -> 5653 bytes
-rw-r--r--khelpcenter/pics/hisc-app-khelpcenter.svgzbin0 -> 75390 bytes
-rw-r--r--khelpcenter/plugins/Applications/.directory60
-rw-r--r--khelpcenter/plugins/Applications/Makefile.am3
-rw-r--r--khelpcenter/plugins/Makefile.am9
-rw-r--r--khelpcenter/plugins/Manpages/.directory60
-rw-r--r--khelpcenter/plugins/Manpages/Makefile.am4
-rw-r--r--khelpcenter/plugins/Manpages/man1.desktop74
-rw-r--r--khelpcenter/plugins/Manpages/man2.desktop75
-rw-r--r--khelpcenter/plugins/Manpages/man3.desktop76
-rw-r--r--khelpcenter/plugins/Manpages/man4.desktop81
-rw-r--r--khelpcenter/plugins/Manpages/man5.desktop81
-rw-r--r--khelpcenter/plugins/Manpages/man6.desktop82
-rw-r--r--khelpcenter/plugins/Manpages/man7.desktop80
-rw-r--r--khelpcenter/plugins/Manpages/man8.desktop79
-rw-r--r--khelpcenter/plugins/Manpages/man9.desktop62
-rw-r--r--khelpcenter/plugins/Manpages/mann.desktop81
-rw-r--r--khelpcenter/plugins/Scrollkeeper/.directory9
-rw-r--r--khelpcenter/plugins/Scrollkeeper/Makefile.am3
-rw-r--r--khelpcenter/plugins/Scrollkeeper/scrollkeeper.desktop2
-rw-r--r--khelpcenter/plugins/Tutorials/.directory108
-rw-r--r--khelpcenter/plugins/Tutorials/Makefile.am5
-rw-r--r--khelpcenter/plugins/Tutorials/quickstart.desktop153
-rw-r--r--khelpcenter/plugins/Tutorials/visualdict.desktop155
-rw-r--r--khelpcenter/plugins/applets.desktop85
-rw-r--r--khelpcenter/plugins/contact.desktop83
-rw-r--r--khelpcenter/plugins/faq.desktop80
-rw-r--r--khelpcenter/plugins/info.desktop80
-rw-r--r--khelpcenter/plugins/kcontrolmodules.desktop87
-rw-r--r--khelpcenter/plugins/kicmodules.desktop87
-rw-r--r--khelpcenter/plugins/kioslaves.desktop35
-rw-r--r--khelpcenter/plugins/konqplugins.desktop85
-rw-r--r--khelpcenter/plugins/links.desktop77
-rw-r--r--khelpcenter/plugins/support.desktop83
-rw-r--r--khelpcenter/plugins/userguide.desktop78
-rw-r--r--khelpcenter/plugins/welcome.desktop83
-rw-r--r--khelpcenter/plugintraverser.cpp117
-rw-r--r--khelpcenter/plugintraverser.h52
-rw-r--r--khelpcenter/prefs.kcfgc6
-rw-r--r--khelpcenter/scopeitem.h50
-rw-r--r--khelpcenter/scrollkeepertreebuilder.cpp200
-rw-r--r--khelpcenter/scrollkeepertreebuilder.h59
-rw-r--r--khelpcenter/searchengine.cpp502
-rw-r--r--khelpcenter/searchengine.h151
-rw-r--r--khelpcenter/searchhandler.cpp249
-rw-r--r--khelpcenter/searchhandler.h97
-rw-r--r--khelpcenter/searchhandlers/Makefile.am10
-rw-r--r--khelpcenter/searchhandlers/README.searchhandlers61
-rw-r--r--khelpcenter/searchhandlers/docbook.desktop6
-rw-r--r--khelpcenter/searchhandlers/htdig.desktop6
-rw-r--r--khelpcenter/searchhandlers/htdig_long.html2
-rwxr-xr-xkhelpcenter/searchhandlers/khc_docbookdig.pl.in221
-rwxr-xr-xkhelpcenter/searchhandlers/khc_htdig.pl.in148
-rwxr-xr-xkhelpcenter/searchhandlers/khc_htsearch.pl117
-rwxr-xr-xkhelpcenter/searchhandlers/khc_mansearch.pl84
-rw-r--r--khelpcenter/searchhandlers/man.desktop5
-rw-r--r--khelpcenter/searchwidget.cpp392
-rw-r--r--khelpcenter/searchwidget.h107
-rw-r--r--khelpcenter/table-of-contents.xslt26
-rw-r--r--khelpcenter/testmetainfo.cpp119
-rw-r--r--khelpcenter/toc.cpp271
-rw-r--r--khelpcenter/toc.h72
-rw-r--r--khelpcenter/treebuilder.cpp35
-rw-r--r--khelpcenter/treebuilder.h49
-rw-r--r--khelpcenter/version.h7
-rw-r--r--khelpcenter/view.cpp387
-rw-r--r--khelpcenter/view.h94
145 files changed, 15795 insertions, 0 deletions
diff --git a/khelpcenter/COPYING b/khelpcenter/COPYING
new file mode 100644
index 00000000..0b84a43f
--- /dev/null
+++ b/khelpcenter/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 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.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. 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 program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; 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.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/khelpcenter/DESIGN b/khelpcenter/DESIGN
new file mode 100644
index 00000000..003423f5
--- /dev/null
+++ b/khelpcenter/DESIGN
@@ -0,0 +1,433 @@
+Design for a possible reimplementation of the KDE help center
+=============================================================
+
+Preludium
+---------
+This document presents an alternative design for a 'help center' applicaiton
+in KDE. Lines which start with a # are supposed to be thoughts I had while
+writing this, much like the stuff you write on the side of a page when reading
+a book.
+
+Lines starting with ## were added by my as further comments - Cornelius
+
+And I'll have the ### lines - Lauri
+
+General
+-------
+- main() instantiates a KHC::Application
+- KHC::Application() deals with parsing the commandline parameters and
+ instantiates a KHC::MainWindow
+- KHC::MainWindow creates the main UI, setting up actions, using a QSplitter
+ as it's mainwidget to separate a KHC::Navigator at the left from a KHC::View
+ at the right
+
+That's the simple part. ;-)
+
+## Apparently already done ;-)
+
+KHC::Navigator
+--------------
+
+KHC::Navigator inherits QTabWidget and provides, on two tabs, a
+KHC::ContentsTab object and a KHC::SearchTab object.
+
+## KHC::Navigator shouldn't inherit from QTabWidget. This limits flexibility.
+## It can create a QTabWidget instance as aggregate just as well.
+
+# I fear premature generalization ("We could need that bit of flexibility one
+# day), aggregation adds a level of indirection through a pointer variable as
+# well. I would prefer not making the system more complex as long as we cannot
+# predict changes which justify doing so.
+
+1.) KHC::ContentsTab provides the following entires:
+ - Welcome to KDE
+ - KDE user's manual
+ - KDE FAQ
+ - Contact information
+ - Supporting KDE
+
+# Should we create an extra item for these five and put them in there?
+# Something like "General KDE" or so? OTOH that makes them less visible, and
+# these are really ought to be seen. - Frerich
+
+## The items are ok, in principle, but we should have a look at the content of
+## the documents they point at. This document could benefit from some attention.
+
+### Yes, they would. Also, there are license issues with one of them.
+### I'd personally like to do an entire rewrite of the User Manual,
+### without GPL encumbrance and sans the content that hasn't changed since
+### KDE 1.x days. The odds of me getting this done before KDE 3.1, slim to fair.
+
+
+ - Application manuals
+ - Tutorials
+ - UNIX man pages
+ - UNIX info pages
+ - Glossary
+
+# Do we really need this "Tutorials" item at all? right now it holds only two
+# items, perhaps we can get rid of it. - Frerich
+
+## Yes, please.
+
+### There should be a "General" area, where documentation that isn't
+### attached directly to an application can go. Tutorials might not be
+### the best name for it I agree, but there is now some further content to
+### add (the DCOP tutorial, for example, or any of the numerous tutorials
+### on the websites, documenting things that aren't in the handbooks.q
+
+# Alright, after some talk on IRC this structure evolved:
+#
+# - Tasks - contains short, three to four paragraph documents about how to
+# solve an everyday task, examples:
+# Browsing the web
+# Send and receive email
+# How to view images
+# Playing sound files
+# Installing new KDE themes
+# How to configure KDE fonts
+# Getting in touch with KDE contributors
+# Supporting the KDE team
+#
+# - Guides - slightly longer, Mini-HOWTO style guides (about three to four
+# pages long, perhaps) which talk about tackling jobs which don't
+# occur very often, examples:
+### I don't know about limiting the length. Some of these topics can stand
+### a much longer document, but one of the things that differentiates them
+### from the references is that they are not specific to a single application,
+### nor are they complete references in the manner of the "KDE User Guide"
+### Specificaly, the dcop tutorial we have is about 15 pages already, but if
+### the user is interested in the topic, that isn't over much, and it's full of
+### examples
+# How to debug KDE programs
+# Sending useful KDE bug reports
+# Extending KDE's service menus
+# Taking advantage of KDE's DCOP facilities
+# Creating panel applets
+# Phrasing questions most effectively
+#
+# - References - references. :-)
+# KDE API reference
+# KDE application manuals
+# Info pages
+# Man pages
+# FAQ
+# User's manual
+#
+# - Glossary - same as always.
+# - By topic
+# - Alphabetically
+#
+# My primary argument for such a structure is that it resembles a
+# task-oriented interface much more closely than the simple list of
+# application manuals. Imagine a user new to KDE who has a fairly precise
+# description of what he's trying to do in mind (think "I want to view an
+# image file") but no idea what tool to use for the job. The current list of
+# application manuals requires the user to browse all the manuals which seem
+# relevant, searching for the information he seeks. A task-oriented list
+# solves that issue.
+# This effectively enables people new to KDE in less time to become productive
+# (a task-oriented list isn't so useful for peoplew ho are familiar with KDE's
+# applications, of course).
+# Implementation-wise, we should perhaps stop using a KListView and use a
+# KOffice-style component selection widget like koshell has at the left?
+
+The first five items are generated by KHC::Navigator itself and are direct
+links to KDE documentations. The work of generating each of the last four
+items is (with one exception) delegated to four helper classes, which inherit a
+'KHC::TreeBuilder' class which has the following interface:
+
+class KHC::TreeBuilder
+ virtual void build( KListViewItem *parent ) = 0;
+
+## What about the trees generated as children of the contents list view?
+
+# Oops, that's a typo, what you mean is what I originally intented: a
+# TreeBuilder should take a 'KListView' as it's parent, subclasses can then
+# overload that method (such as the KHC::TOCBuilder which will want to provide
+# a build( KListViewItem *parent ) method).
+
+# This concept of using a TreeBuilder baseclass might make it possible to turn
+# all the classes which use that interface into plugins. That way we could
+# e.g. have a ScrollKeeper plugin. - Frerich
+
+## What exactly do you mean by plugin? A shared library loaded at run time or
+## the desktop file based insertion of documents into the help center?
+
+# The former.
+
+The classes which inherit this interface are:
+ - KHC::ManualTreeBuilder: responsible for generating the tree below the
+ "Application manuals" item
+ - KHC::TOCBuilder: responsible for generating a TOC tree below each of the
+ manual trees items, so that you can choose Application
+ Manuals->Editors->KWrite->Using KWrite->Menu bar transparently. This is
+ the only builder which is not instantiated by KHC::ContentsTab but
+ instead instantiated by KHC::ManualTreeBuilder
+ - KHC::TutorialTreeBuilder: responsible for generating the tree below the
+ "Tutorials" item
+ - KHC::ManTreeBuilder: responsible for building the tree below the "UNIX
+ man pages" item
+ - KHC::InfoTreeBuilder: responsible for building the tree below the "UNIX
+ info pages" item
+ - KHC::GlossaryTreeBuilder: guess what
+
+## - KHC::ScrollkeeperTreeBuilder
+
+## It's certainly a good idea to move stuff like the info and man pages and
+## scrollkeeper support to its own classes. What I consider as important is
+## that the concept of representing the documentation by desktop meta files is
+## used as far as possible. This makes the system very flexible and extandable.
+
+2.) KHC::SearchTab provides a widget which lets the search through all
+available help repositories, also defining some flags such as 'Search by
+regexp' or 'Search case sensitive'.
+
+# I think this means that we have to create a 'DataCollection' class which
+# gets inherited by all classes which are "searchable". DataCollections should
+# also be able to contains multiple child DataCollection, so that we have e.g.
+# one DataCollection per application manual, and one "Manuals" collection
+# which contains all the application manual collections.
+# We'd probably also need a DataCollection for the info pages and man pages.
+# And later, in the far future, we might extent this concept to web searches,
+# so that e.g. Google represents a DataCollection which we can query.
+# I'm not yet decided how to do that properly, perhaps using multiple
+# inheritance, so that each TOCBuilder is a DataCollection - naw, we'd rather
+# have a "TableOfContents" class which contains a TOCBuilder, and is a
+# datacollection? Hm, not sure.
+# In any case DataCollections should some sort of plugins, so that we can add
+# e.g. new web search interfaces lateron.
+# - Frerich
+
+## What you call a DataCollection is currently represented by the DocEntry
+## objects. Each DocEntry object represents a document or a collection of
+## documents. It has information about the name and description of the
+## document, the location and how it can be searched.
+##
+## Currently this information is based on URLs or file names and is optimized
+## to be used by scripts, e.g. CGI scripts. A little exception from this is
+## the htdig support where just a keyword "SearchMethod=htdig" is put in the
+## desktop file and the help center figures out how to perform that search by
+## using a special class. This could be extended to cover other search methods
+## like web searches or special search methods optimized for certain kind of
+## documents.
+
+# I just thought about it - isn't that a bit overkill for the web search
+# stuff? I just thought about it - all we need to do is to copy the .desktop
+# files (at least some of them, like the ones for google, yahoo and excite)
+# from the enhanced browsing thing and treat those as plugin .desktop files.
+# We could show them in a listview on the Search tab, each found search engine
+# being represented by a checkable listview item. So, we just let the user
+# enter a term, replace the \{@} placeholder in the URIs specified in the
+# selected .desktop files with that term, send out a request via KIO and show
+# the results in our KHTMLPart (after all KHC::View is a KHTMLPart already). A
+# problem with this: How to display the multiple HTML pages returned by the
+# selected search engines? Using a QSplitter to split multiple KHTMLParts?
+# Hmm... just wondered... perhaps we can work around that by not showing the
+# returned HTML data at all but rather use a XSLT script (that is, one XSLT
+# script per web search) which transforms the returned search results into a
+# common format - that way, we could also filter out duplicates and then
+# transform that filtered output into a nice, uniform HTML page. How about
+# that?
+
+# I like this idea very much, I just thought it and noticed you wrote this
+# down already. What I thought of was having a .desktop/.xslt file pair per
+# search engine: each .desktop file holds at least the name of the engine (for
+# the listview) and a search URI with a placeholder, just like in your scenario.
+# In additionl there could be a X-KHelpCenter-XSLT key which defines which .xslt
+# stylesheet to use for that particular search engine. We then query that search
+# engine by replacing the placeholder in the URI with whatever the user entered
+# and hand it to KIO. All the HTML returned by the various search engines gets
+# then transformed into a custom, intermediate, XML dialect, using the XSLT
+# stylesheets define in the .desktop files. Using that intermediate step we
+# can nicely drop duplicate hits, for example, or create a list of hits in the
+# sidebar (much like http://www.copernic.com does). After that, we can use
+# another XSLT stylesheet to transform that cleaned XML tree into HTML which
+# we then feed to our KHTMLView. Since we then have one unified output, we don't
+# need to worry about having multiple KHTMLParts, and it's also nice because
+# the user doesn't see which search engine returned which hit.
+
+# A problem with this would be that we cannot tell how a particular search
+# engine treats boolean expressions (e.g. some search engines use 'foo AND bar',
+# others use '+foo +bar', a third variation is '"foo bar"'). We thus cannot
+# replace the placeholder in the URI but first have to translate the syntax
+# entered by the user into a syntax which is appropriate for each single news
+# engine. Right now I don't know how we could do this with just a .desktop/.xslt
+# pair. We could always use fullblown C++ plugins which hold code which is able
+# to do that translation, but I would really prefer to stick with .desktop files
+# now since they're much easier to create.
+
+# Another thing which would speak in favor of C++ plugins: different search
+# engines support different features (like, google can search more than just the
+# web, and you can sometimes tell a search engine to list only results in a
+# certain language, or with a certain encoding), so it would be nice if we could
+# let the user access those features: through a dialog which has to be tailored
+# to the possibilities of the respective search engine. I wonder whether we
+# could have some sort of XML tree which defines how an UI should look like, and
+# then let KHelpCenter create a dialog using that XML markup, but that idea is
+# very vague right now.
+
+# Hmm, I just tried it and the XSLT idea didn't really take off: the problem
+# is that many HTML pages returned by Google, Yahoo & co. don't seem to be
+# valid XML, which is why tools such as meinproc or xsltproc refuse to process
+# themm. :-/
+
+KHC::View
+---------
+KHC::View inherits KHTMLPart and does the actual job of showing some sort of
+document. Most importantly, it has a slot which passes it a KURL pointing to a
+document to show. KHC::View will invoke kio_help if necessary (if the URL's
+protocol == "help") by itself and otherwise use the plain URL.
+
+# TODO: Things I didn't really think about yet: the interface between the
+# navigator and the view. I think this has to be a bidirectional association
+# since the navigator can change the view (e.g. by clicking on a manual which
+# shows it in the view), but the view can also change the navigator (think of
+# clicking on a 'See also' link in the glossary which should also scroll to
+# the corresponding entry in the navigator).
+
+## That's a very important aspect. We should have one central place where all
+## document requests are processed and the necessary actions (like updating
+## the navigator, loading a new page, caching the search results, etc.) are
+## done.
+##
+## The TreeBuilder might need some interface to tell, if a certain URL exist
+## in their tree, to make it possible to select content entries which aren't
+## created yet, because they are only created on demand (like the application
+## manuals).
+
+# Very good idea. Perhaps I think iterating over a list of TreeBuilder
+# instances and doing something like 'if ((*it)->canHandle(url))
+# (*it)->selectItem(url)' which checks whether a TreeBuilder provides an item
+# which corresponds to an URL (hmm, this makes me think, TreeBuilder is a bad
+# name. Perhaps just 'Tree'?) and selects it (using
+# QListView::ensureItemVisible() or so) if requested. This probably implies.
+# that a TreeBuilder needs an internal QMap<KURL, QListViewItem *>.
+
+# Also, the whole search engine needs more thought, that DataCollection idea
+# seems promising to me but I'm not yet decided on how to do it properly.
+
+## See above. We already have something which isn't too bad, I think.
+
+# I just thought about this a bit, I think KHC::MainWindow should act as the
+# interface between KHC::Navigator and KHC::View.
+
+## I would prefer to have an extra class which does no GUI stuff, but passes
+## URL requests around, does the needed processing and stores data, if needed
+## (e.g. caching search results).
+
+# Agreed.
+
+## One very important aspect of the help center is that it has to be fast. It's
+## not acceptable to wait several seconds after clicking on the Help menu of an
+## application. We should think about that. Perhaps we can do some tricks like
+## showing the main window before creating the other widgets and processing data
+## or something similar. We could also think about creating more stuff only on
+## demand.
+
+# My perception is that filling the Navigator's listview takes a significant
+# amount of time, just like setting up the KHTML view (loading the stylesheet,
+# showing the welcome page). We could easily do taht in the background - show
+# the mainwindow, then tell the TreeBuilders to start populating (using a
+# QTimer with a timeout of 0, for a snappy GUI). Since they're collapsed at
+# the start, the users won't even notice (and we can "fake" that they're
+# already populated by calling setExpandable(true) for all of them (or letting
+# them do that themselves) at the start.
+
+## Finally a crazy idea: Wouldn't it be cool, if we would make the manuals more
+## interactive. So when you read about a certain menu or a certain dialog of an
+## application you can click on a link in the manual and the menu or dialog gets
+## opened in the real application, or some widgets get highlghted in the real
+## application. Such a feature could also be used to create interactive
+## tutorials, where you have a small helpcenter window and the application next
+## to each other on the screen and you can go through the tutorial step by step
+## and practice with the real application while reading the instructions.
+## With the help of DCOP it shouldn't be too hard to implement such an
+## interactive help system. Maybe it's even possible to do it in a general way
+## in the libs, so that application authors don't have to think about that
+## feature.
+
+# Hmm, that's an interesting idea. That takes KHelpCenter way beyond what it's
+# currently doing. I can imagine this: we introduce a virtual "dcop" protocol,
+# so that e.g. <ulink url="dcop:/kfortune/KFortuneIface/nextFortune"/>
+# represents the DCOP call 'dcop kfortune KFortuneIface nextfortune'.
+# KHelpCenter catches that protocol (oh dear, a lot of special cases with
+# gloss, info etc. already - guess another one won't hurt). That looks like a
+# good way for encapsulating DCOP calls.
+# Now, the problem is - the application has to provide a dedicated
+# "documentation" DCOP interface for this, with lots of calls for highlighting
+# the various widgets (hm, this probably means taht we can skip the first two
+# parts in our 'dcop' URL syntax, the application is known anyway, and the
+# interface is hardcoded in KHelpCenter).
+# So, what could happen is this: We have a piece of HTML in the documentation
+# for our SuperApp application which goes like 'The
+# <a href="dcop:highlightConnectButton">button labelled Connect</a> makes
+# SuperApp establish a connection.' - the user clicks on that link,
+# KHelpCenter catches a dcop: URL, checks whether SuperApp has already been
+# started. If not, it starts a SuperApp process and does the dcop call 'dcop
+# SuperApp DocIface highlightConnectButton' and SuperApp starts highlighting
+# that connect button. The thing is that this requires a lot of work on the
+# application side. The idea is very cool, but we'd have to think about
+# outsourceing parts of that functionality, either to KHelpCenter, or to
+# kdelibs.
+
+## And another idea: The WhatsThis help texts describe all widgets of an
+## application (provided that the texts are set by the developers). Currently
+## they aren't accessible very easily. You have to go to a special mode and
+## can then click on one widget after another to get the help, if there is one.
+## There is no visual indication which widgets have help and which not. But the
+## application knows about the WhatsThis helps. Perhaps it's possible to use
+## the Qt object inspection stuff to extract all the texts and put them on an
+## automatically generated screenshot of the corresponding dialog and put this
+## graphic into the docs. Maybe it's even possible to do this at run-time and
+## decorate dialogs with all WhatsThis helps at once, if the user triggers this
+## mode.
+
+# Hmm yes, that should be possible. Take the toplevel widget, use
+# QObject::children() and iterate over all children, use QToolTip::textFor() to
+# check whether the given qwidget has a tooltip and if so, use QToolTip::tip()
+# to show the tooltip.
+# One could probably add a standard dcop call to KMainWindow, like
+# "showAllToolTips". KSnapShot could get a QCheckBox "Show all tooltips", and
+# if that box is checked it tells the selected window to show all it's
+# tooltips via that DCOP call right before it does the snapshot. The thing is
+# - is it possible to map the WinID of the window the user clicked on to
+# the process name we should send your DCOP call to?
+
+## One thing we should also keep in mind is that it might be useful to provide
+## the help center as a component. FOr example KDevelop has a very similar
+## thing. It would be much nicer, if it could reuse the KHelpcenter code. This
+## would probbaly also mean to at a DoxygenTreeBuilder or something similar.
+
+# That probably implies that instead of a QSplitter which holds the Navigator
+# and the View, we'd have a KHC::MainWidget KPart which in turn aggregates the
+# splitter. The DoxygenTreeBuilder sounds like a reason to make TreeBuilders
+# real plugins, with dynamically loaded libraries, so that KDevelop or other
+# "IDE"-like applications (perhaps a KOffice help system?) can have their
+# customized tree builders.
+
+Font Configuration
+------------------
+
+### Many bug reports on KHelpCenter not honouring KHTML font settings,
+### which is odd, because the stylesheet is intentionally loose,
+### specifying only "sans-serif" as the font face.
+
+### Ideas to fix:
+
+### Help pages already make heavy use of the cascading feature of CSS, we
+### ought to be able to leverage that by writing to perhaps the
+### kde-localized.css file or a copy of it in $KDEHOME. There is already
+### code in KControl to create a user CSS stylesheet, and we probably only
+### need to configure the size and the face for KHC.
+
+### Or, fix whatever is the reason KHC doesn't follow the rules. It could
+### be encoding related, the help pages specify utf-8 as the encoding, and
+### previous incarnations of the KHTML settings allowed fonts set on a
+### per-encoding basis (at which time, this was apparently working, the bug
+### reports dropped off, and only returned post KDE 3.0
+
+# FWIW I added a simple font configuration facility a while back, which should
+# IMHO be sufficient for the vast majority of users.
+
+// vim:tw=78
diff --git a/khelpcenter/Help.desktop b/khelpcenter/Help.desktop
new file mode 100644
index 00000000..26f21f01
--- /dev/null
+++ b/khelpcenter/Help.desktop
@@ -0,0 +1,86 @@
+[Desktop Entry]
+Exec=khelpcenter
+Icon=khelpcenter
+DocPath=khelpcenter/index.html
+Type=Application
+Terminal=false
+Name=Help
+Name[af]=Hulp
+Name[ar]=مساعدة
+Name[be]=Дапамога
+Name[bg]=Помощ
+Name[bn]=সাহায্য
+Name[br]=Skoazell
+Name[bs]=Pomoć
+Name[ca]=Ajuda
+Name[cs]=Nápověda
+Name[csb]=Pòmòc
+Name[cy]=Cymorth
+Name[da]=Hjælp
+Name[de]=Hilfe
+Name[el]=Βοήθεια
+Name[eo]=Helpo
+Name[es]=Ayuda
+Name[et]=Abi
+Name[eu]=Laguntza
+Name[fa]=کمک
+Name[fi]=Ohje
+Name[fr]=Aide
+Name[ga]=Cabhair
+Name[gl]=Axuda
+Name[he]=עזרה
+Name[hr]=Pomoć
+Name[hu]=Segítség
+Name[id]=Keterangan bantu
+Name[is]=Hjálp
+Name[it]=Aiuto
+Name[ja]=ヘルプ
+Name[ka]=დახმარება
+Name[kk]=Анықтама
+Name[km]=ជំនួយ
+Name[ko]=도움말
+Name[lo]=ລະບົບຊ່ວຍເຫືລອ
+Name[lt]=Pagalba
+Name[lv]=Palīdzība
+Name[mk]=Помош
+Name[mn]=Тусламж
+Name[ms]=Bantuan
+Name[nb]=Hjelp
+Name[nds]=Hülp
+Name[ne]=मद्दत
+Name[nl]=Documentatie
+Name[nn]=Hjelp
+Name[nso]=Thuso
+Name[oc]=Ajuda
+Name[pa]=ਸਹਾਇਤਾ
+Name[pl]=Pomoc
+Name[pt]=Ajuda
+Name[pt_BR]=Ajuda
+Name[ro]=Ajutor
+Name[ru]=Справка
+Name[rw]=Ifashayobora
+Name[se]=Veahkki
+Name[sk]=Pomocník
+Name[sl]=Pomoč
+Name[sr]=Помоћ
+Name[sr@Latn]=Pomoć
+Name[ss]=Sita
+Name[sv]=Hjälp
+Name[ta]=உதவி
+Name[te]=సహాయం
+Name[tg]=Роҳнамо
+Name[th]=ระบบช่วยเหลือ
+Name[tr]=Yardım
+Name[tt]=Yärdäm
+Name[uk]=Довідка
+Name[uz]=Yordam
+Name[uz@cyrillic]=Ёрдам
+Name[ven]=Thuso
+Name[vi]=Trợ giúp
+Name[wa]=Aidance
+Name[xh]=Uncedo
+Name[zh_CN]=帮助
+Name[zh_TW]=求助
+Name[zu]=Usizo
+Categories=Qt;KDE;Core;
+OnlyShowIn=KDE;
diff --git a/khelpcenter/Makefile.am b/khelpcenter/Makefile.am
new file mode 100644
index 00000000..24c1f374
--- /dev/null
+++ b/khelpcenter/Makefile.am
@@ -0,0 +1,57 @@
+SUBDIRS = plugins pics searchhandlers
+
+INCLUDES = $(all_includes)
+METASOURCES = AUTO
+
+bin_PROGRAMS = khc_indexbuilder
+lib_LTLIBRARIES =
+
+khc_indexbuilder_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+khc_indexbuilder_LDADD = $(LIB_KDECORE)
+khc_indexbuilder_SOURCES = khc_indexbuilder.cpp
+
+kdeinit_LTLIBRARIES = khelpcenter.la
+
+khelpcenter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+khelpcenter_la_LIBADD = $(LIB_KHTML)
+khelpcenter_la_SOURCES = navigator.cpp \
+ navigatoritem.cpp navigatorappitem.cpp view.cpp \
+ searchwidget.cpp searchengine.cpp \
+ docmetainfo.cpp docentrytraverser.cpp formatter.cpp \
+ glossary.cpp toc.cpp mainwindow.cpp docentry.cpp htmlsearch.cpp \
+ history.cpp application.cpp searchwidget.skel treebuilder.cpp \
+ infotree.cpp mainwindow.skel \
+ kcmhelpcenter.cpp htmlsearchconfig.cpp kcmhelpcenter.skel \
+ fontdialog.cpp plugintraverser.cpp scrollkeepertreebuilder.cpp \
+ prefs.kcfgc searchhandler.cpp
+
+#kcm_helpcenter_la_LDFLAGS = $(KDE_RPATH) -module -avoid-version \
+# $(all_libraries) -no-undefined
+#kcm_helpcenter_la_LIBADD = $(LIB_KIO)
+#kcm_helpcenter_la_SOURCES = kcmhelpcenter.cpp docmetainfo.cpp \
+# docentrytraverser.cpp docentry.cpp htmlsearch.cpp \
+# htmlsearchconfig.cpp
+
+EXTRA_PROGRAMS = testmetainfo
+
+testmetainfo_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+testmetainfo_LDADD = $(LIB_KDECORE) docentry.lo docmetainfo.lo \
+ docentrytraverser.lo htmlsearch.lo
+testmetainfo_SOURCES = testmetainfo.cpp
+
+service_DATA = khelpcenter.desktop
+servicedir = $(kde_servicesdir)
+
+xdg_apps_DATA = Help.desktop
+
+#xdg_apps_DATA = kcmhelpcenter.desktop
+
+rc_DATA = khelpcenterui.rc intro.html.in glossary.html.in table-of-contents.xslt \
+ glossary.xslt index.html.in
+rcdir = $(kde_datadir)/khelpcenter
+
+kde_kcfg_DATA = khelpcenter.kcfg
+
+messages: rc.cpp
+ $(EXTRACTRC) `find . -name "*.kcfg"` >> rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/khelpcenter.pot
diff --git a/khelpcenter/README.htdig b/khelpcenter/README.htdig
new file mode 100644
index 00000000..c4981035
--- /dev/null
+++ b/khelpcenter/README.htdig
@@ -0,0 +1,14 @@
+To make use of the full-text search function in khelpcenter,
+you need ht://dig.
+
+ht://dig is a HTML indexing and searching tool.
+
+You can get it from http://www.htdig.org.
+
+NOTE: If you install htdig from source, make sure
+that you put the 'htsearch' as well as the 'htdig'
+and 'htmerge' binaries into your PATH.
+
+Per default, 'htsearch' goes to some cgi-bin
+directory.
+
diff --git a/khelpcenter/README.metadata b/khelpcenter/README.metadata
new file mode 100644
index 00000000..733bb5ef
--- /dev/null
+++ b/khelpcenter/README.metadata
@@ -0,0 +1,129 @@
+KHelpCenter documentation meta data structure
+=============================================
+
+KHelpCenter uses meta data files which describe the documentation available in
+the system. Each document is represented by a meta data file and shown as an
+entry in the KHelpCenter navigation tree view. The meta data contains
+information about title and short description of the document, the location of
+the document and some more information like how to search the document and
+translations of title and description. Document hierarchy is represented as
+hierarchy of the meta data files. Directories are also described by a meta data
+file which contains the same information as a document meta data file.
+
+Format of the meta data files
+-----------------------------
+
+The meta files adhere to the Desktop Entry Standard
+(http://www.freedesktop.org/Standards/desktop-entry-spec). Documentation
+specific extensions are covered by an own namespace using the prefix "X-DOC-".
+The following table describes all keys which are currently used by
+KHelpCenter:
+
+Key Value Description
+
+Name string Title of document
+Name[xx] string Translated title for language xx
+Comment string Short description of document
+Comment[xx] string Translated short description for
+ Language xx
+Icon string Name of icon for document
+DocPath URI Location of document. In addition to the
+ standard URI schemes like http: and file:
+ all schemes which are supported through
+ kioslaves can be used. In particular the
+ following non-standard URI schemes are
+ supported:
+ help: KDE manual identified by app name
+ ghelp: GNOME manual identified by app name
+ man: man page
+ info: info page
+ cgi: output of CGI script
+DocPath[xx] URI Language specific location for
+ language xx
+Lang langcode Language of document
+X-DOC-Identifier string Unique identifier for document, if this
+ entry is not present the base name of the
+ file is used as identifier
+X-DOC-Indexer command Command used for creating a search index
+ for the document.
+ The following symbols are replaced by the
+ corresponding values:
+ %f - Filename
+X-DOC-IndexTestFile filename Name of file whose existence indicates
+ the existence of a usable search index
+X-DOC-Search command Command used for searching, the output
+ of the command should be HTML which is
+ shown in KHelpCenter.
+ The following symbols in the command are
+ replaced by the corresponding values:
+ %k - Words to be searched for
+ %n - Maximum number of results
+ %m - Method for combining search words,
+ can be 'and' or 'or'
+ %l - Language of documents to be searched
+ %s - Scope of search. This is a list of
+ identifiers as given by the
+ X-DOC-Identifier entry or the bas
+ name of the desktop file if not
+ present.
+X-DOC-SearchMethod string If this entry is 'htdig' htdig is used to
+ index and search the document. The
+ Indexer, IndexTestFile and Search entries
+ aren't required in this case.
+X-DOC-SearchEnabledDefault bool If set to 'true' the document is searched
+ by default, if set to 'false' it is not.
+ This setting is overridden by user
+ selected search scopes.
+X-DOC-Weight int A number indicating the position of the
+ document within the list of siblings. A
+ greater weight indicates that the document
+ is 'heavier', thus shown below 'lighter'
+ documents. The default weight is 0.
+X-KDE-KHelpcenter string If this entry is set to one of the
+ following values a set of documents
+ generated by other means than desktop file
+ meta info is inserted at the place
+ specified by the desktop file:
+ 'apps' manuals of applications
+ from the start menu
+ 'scrollkeeper' scrollkeeper docs
+ 'applets' panel applet docs
+ 'kinfocenter' kinfocenter docs
+ 'kcontrol' kcontrol module docs
+ 'konqueror' konqueror plugin docs
+ 'kioslave' kioslave docs
+ 'info' info pages
+X-DOC-DocumentType string Type of document. The type is used to look
+ up corresponding search handlers.
+
+Meta File Location
+------------------
+
+A list of directories given by the config entry "MetaInfoDirs" in the "General"
+group of the help center configuration file "khelpcenterrc" (at
+$KDEDIRS/share/config) is scanned for desktop files. They are merged to a common
+hierarchy. If the "MetaInfoDirs" entry is empty the directory at
+$KDEDIRS/share/apps/khelpcenter/plugins is used.
+
+Document Hierarchy
+------------------
+
+The hierarchy of the documents shown in the help center is reflected by the
+hierarchy of the desktop files in the filesystem. Directories can have an
+associated desktop file with the name ".directory". It can contain all the
+keys described above.
+
+Language handling
+-----------------
+
+In addition to translation of meta information like title and short description
+of documents which is contained in the meta file, translations of whole
+documents are handled. Each translation of a document has an own desktop file.
+The language of the document is indicated by adding the language code as
+additional suffix to the the filename of the desktop file. The language suffix
+is added before the ".desktop" suffix (Example: 'apache.de.desktop' would be the
+file name for the german translation of the apache documentation).
+
+KHelpCenter shows only the documents whose language is contained in the list of
+used languages configured for the desktop in the control center. A document
+corresponding to a desktop file without language suffix is always shown.
diff --git a/khelpcenter/application.cpp b/khelpcenter/application.cpp
new file mode 100644
index 00000000..3530b274
--- /dev/null
+++ b/khelpcenter/application.cpp
@@ -0,0 +1,89 @@
+ /*
+ * This file is part of the KDE Help Center
+ *
+ * Copyright (c) 2002 Frerich Raabe <raabe@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "application.h"
+#include "mainwindow.h"
+#include "version.h"
+
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+
+using namespace KHC;
+
+Application::Application() : KUniqueApplication(), mMainWindow( 0 )
+{
+}
+
+int Application::newInstance()
+{
+ if (restoringSession()) return 0;
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ KURL url;
+ if ( args->count() )
+ url = args->url( 0 );
+
+ if( !mMainWindow ) {
+ mMainWindow = new MainWindow;
+ setMainWidget( mMainWindow );
+ mMainWindow->show();
+ }
+
+ mMainWindow->openUrl( url );
+
+ return KUniqueApplication::newInstance();
+}
+
+static KCmdLineOptions options[] =
+{
+ { "+[url]", I18N_NOOP("URL to display"), "" },
+ KCmdLineLastOption
+};
+
+extern "C" int KDE_EXPORT kdemain( int argc, char **argv )
+{
+ KAboutData aboutData( "khelpcenter", I18N_NOOP("KDE Help Center"),
+ HELPCENTER_VERSION,
+ I18N_NOOP("The KDE Help Center"),
+ KAboutData::License_GPL,
+ I18N_NOOP("(c) 1999-2003, The KHelpCenter developers") );
+
+ aboutData.addAuthor( "Cornelius Schumacher", 0, "schumacher@kde.org" );
+ aboutData.addAuthor( "Frerich Raabe", 0, "raabe@kde.org" );
+ aboutData.addAuthor( "Matthias Elter", I18N_NOOP("Original Author"),
+ "me@kde.org" );
+ aboutData.addAuthor( "Wojciech Smigaj", I18N_NOOP("Info page support"),
+ "achu@klub.chip.pl" );
+
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ KCmdLineArgs::addCmdLineOptions( options );
+ KApplication::addCmdLineOptions();
+
+ KHC::Application app;
+
+ if ( app.isRestored() ) {
+ RESTORE( MainWindow );
+ }
+
+ return app.exec();
+}
+
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/application.h b/khelpcenter/application.h
new file mode 100644
index 00000000..7344dddf
--- /dev/null
+++ b/khelpcenter/application.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the KDE Help Center
+ *
+ * Copyright (C) 2002 Frerich Raabe <raabe@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef APPLICATION_H
+#define APPLICATION_H
+
+#include <kuniqueapplication.h>
+
+namespace KHC {
+
+class MainWindow;
+
+class Application : public KUniqueApplication
+{
+ public:
+ Application();
+
+ virtual int newInstance();
+
+ private:
+ MainWindow *mMainWindow;
+};
+
+}
+
+extern "C" { int kdemain(int argc, char **argv); }
+
+#endif // APPLICATION_H
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/configure.in.in b/khelpcenter/configure.in.in
new file mode 100644
index 00000000..88801ab8
--- /dev/null
+++ b/khelpcenter/configure.in.in
@@ -0,0 +1,2 @@
+dnl AC_OUTPUT(khelpcenter/searchhandlers/khc_docbookdig.pl)
+dnl AC_OUTPUT(khelpcenter/searchhandlers/khc_htdig.pl)
diff --git a/khelpcenter/docentry.cpp b/khelpcenter/docentry.cpp
new file mode 100644
index 00000000..77966451
--- /dev/null
+++ b/khelpcenter/docentry.cpp
@@ -0,0 +1,348 @@
+#include <qregexp.h>
+#include <qfileinfo.h>
+
+#include <kdebug.h>
+#include <kdesktopfile.h>
+#include <kurl.h>
+#include <kstandarddirs.h>
+#include <kapplication.h>
+
+#include "prefs.h"
+
+#include "docentry.h"
+
+using namespace KHC;
+
+DocEntry::DocEntry()
+{
+ init();
+}
+
+DocEntry::DocEntry( const QString &name, const QString &url,
+ const QString &icon )
+{
+ init();
+
+ mName = name;
+ mUrl = url;
+ mIcon = icon;
+}
+
+void DocEntry::init()
+{
+ mWeight = 0;
+ mSearchEnabled = false;
+ mDirectory = false;
+ mParent = 0;
+ mNextSibling = 0;
+}
+
+void DocEntry::setName( const QString &name )
+{
+ mName = name;
+}
+
+QString DocEntry::name() const
+{
+ return mName;
+}
+
+void DocEntry::setSearch( const QString &search )
+{
+ mSearch = search;
+}
+
+QString DocEntry::search() const
+{
+ return mSearch;
+}
+
+void DocEntry::setIcon( const QString &icon )
+{
+ mIcon = icon;
+}
+
+QString DocEntry::icon() const
+{
+ if ( !mIcon.isEmpty() ) return mIcon;
+
+ if ( !docExists() ) return "unknown";
+
+ if ( isDirectory() ) return "contents2";
+ else return "document2";
+}
+
+void DocEntry::setUrl( const QString &url )
+{
+ mUrl = url;
+}
+
+QString DocEntry::url() const
+{
+ if ( !mUrl.isEmpty() ) return mUrl;
+
+ if ( identifier().isEmpty() ) return QString::null;
+
+ return "khelpcenter:" + identifier();
+}
+
+void DocEntry::setInfo( const QString &info )
+{
+ mInfo = info;
+}
+
+QString DocEntry::info() const
+{
+ return mInfo;
+}
+
+void DocEntry::setLang( const QString &lang )
+{
+ mLang = lang;
+}
+
+QString DocEntry::lang() const
+{
+ return mLang;
+}
+
+void DocEntry::setIdentifier( const QString &identifier )
+{
+ mIdentifier = identifier;
+}
+
+QString DocEntry::identifier() const
+{
+ if ( mIdentifier.isEmpty() ) mIdentifier = KApplication::randomString( 15 );
+ return mIdentifier;
+}
+
+void DocEntry::setIndexer( const QString &indexer )
+{
+ mIndexer = indexer;
+}
+
+QString DocEntry::indexer() const
+{
+ return mIndexer;
+}
+
+void DocEntry::setIndexTestFile( const QString &indexTestFile )
+{
+ mIndexTestFile = indexTestFile;
+}
+
+QString DocEntry::indexTestFile() const
+{
+ return mIndexTestFile;
+}
+
+void DocEntry::setWeight( int weight )
+{
+ mWeight = weight;
+}
+
+int DocEntry::weight() const
+{
+ return mWeight;
+}
+
+void DocEntry::setSearchMethod( const QString &method )
+{
+ mSearchMethod = method;
+}
+
+QString DocEntry::searchMethod() const
+{
+ return mSearchMethod;
+}
+
+void DocEntry::setDocumentType( const QString &str )
+{
+ mDocumentType = str;
+}
+
+QString DocEntry::documentType() const
+{
+ return mDocumentType;
+}
+
+QString DocEntry::khelpcenterSpecial() const
+{
+ return mKhelpcenterSpecial;
+}
+
+void DocEntry::enableSearch( bool enabled )
+{
+ mSearchEnabled = enabled;
+}
+
+bool DocEntry::searchEnabled() const
+{
+ return mSearchEnabled;
+}
+
+void DocEntry::setSearchEnabledDefault( bool enabled )
+{
+ mSearchEnabledDefault = enabled;
+}
+
+bool DocEntry::searchEnabledDefault() const
+{
+ return mSearchEnabledDefault;
+}
+
+void DocEntry::setDirectory( bool dir )
+{
+ mDirectory = dir;
+}
+
+bool DocEntry::isDirectory() const
+{
+ return mDirectory;
+}
+
+bool DocEntry::readFromFile( const QString &fileName )
+{
+ KDesktopFile file( fileName );
+
+ mName = file.readName();
+ mSearch = file.readEntry( "X-DOC-Search" );
+ mIcon = file.readIcon();
+ mUrl = file.readPathEntry( "DocPath" );
+ mInfo = file.readEntry( "Info" );
+ if ( mInfo.isNull() ) mInfo = file.readEntry( "Comment" );
+ mLang = file.readEntry( "Lang", "en" );
+ mIdentifier = file.readEntry( "X-DOC-Identifier" );
+ if ( mIdentifier.isEmpty() ) {
+ QFileInfo fi( fileName );
+ mIdentifier = fi.baseName( true );
+ }
+ mIndexer = file.readEntry( "X-DOC-Indexer" );
+ mIndexer.replace( "%f", fileName );
+ mIndexTestFile = file.readEntry( "X-DOC-IndexTestFile" );
+ mSearchEnabledDefault = file.readBoolEntry( "X-DOC-SearchEnabledDefault",
+ false );
+ mSearchEnabled = mSearchEnabledDefault;
+ mWeight = file.readNumEntry( "X-DOC-Weight", 0 );
+ mSearchMethod = file.readEntry( "X-DOC-SearchMethod" );
+ mDocumentType = file.readEntry( "X-DOC-DocumentType" );
+
+ mKhelpcenterSpecial = file.readEntry("X-KDE-KHelpcenter-Special");
+
+ return true;
+}
+
+bool DocEntry::indexExists( const QString &indexDir )
+{
+ QString testFile;
+ if ( mIndexTestFile.isEmpty() ) {
+ testFile = identifier() + ".exists";
+ } else {
+ testFile = mIndexTestFile;
+ }
+
+ if ( !testFile.startsWith( "/" ) ) testFile = indexDir + "/" + testFile;
+
+ return QFile::exists( testFile );
+}
+
+bool DocEntry::docExists() const
+{
+ if ( !mUrl.isEmpty() ) {
+ KURL docUrl( mUrl );
+ if ( docUrl.isLocalFile() && !KStandardDirs::exists( docUrl.path() ) ) {
+// kdDebug(1400) << "URL not found: " << docUrl.url() << endl;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void DocEntry::addChild( DocEntry *entry )
+{
+ entry->setParent( this );
+
+ uint i;
+ for( i = 0; i < mChildren.count(); ++i ) {
+ if ( i == 0 ) {
+ if ( entry->weight() < mChildren.first()->weight() ) {
+ entry->setNextSibling( mChildren.first() );
+ mChildren.prepend( entry );
+ break;
+ }
+ }
+ if ( i + 1 < mChildren.count() ) {
+ if ( entry->weight() >= mChildren[ i ]->weight() &&
+ entry->weight() < mChildren[ i + 1 ]->weight() ) {
+ entry->setNextSibling( mChildren[ i + 1 ] );
+ mChildren[ i ]->setNextSibling( entry );
+ mChildren.insert( mChildren.at( i + 1 ), entry );
+ break;
+ }
+ }
+ }
+ if ( i == mChildren.count() ) {
+ if ( i > 0 ) {
+ mChildren.last()->setNextSibling( entry );
+ }
+ mChildren.append( entry );
+ }
+}
+
+bool DocEntry::hasChildren()
+{
+ return mChildren.count();
+}
+
+DocEntry *DocEntry::firstChild()
+{
+ return mChildren.first();
+}
+
+DocEntry::List DocEntry::children()
+{
+ return mChildren;
+}
+
+void DocEntry::setParent( DocEntry *parent )
+{
+ mParent = parent;
+}
+
+DocEntry *DocEntry::parent()
+{
+ return mParent;
+}
+
+void DocEntry::setNextSibling( DocEntry *next )
+{
+ mNextSibling = next;
+}
+
+DocEntry *DocEntry::nextSibling()
+{
+ return mNextSibling;
+}
+
+bool DocEntry::isSearchable()
+{
+ return !search().isEmpty() && docExists() &&
+ indexExists( Prefs::indexDirectory() );
+}
+
+void DocEntry::dump() const
+{
+ kdDebug() << " <docentry>" << endl;
+ kdDebug() << " <name>" << mName << "</name>" << endl;
+ kdDebug() << " <searchmethod>" << mSearchMethod << "</searchmethod>" << endl;
+ kdDebug() << " <search>" << mSearch << "</search>" << endl;
+ kdDebug() << " <indexer>" << mIndexer << "</indexer>" << endl;
+ kdDebug() << " <indextestfile>" << mIndexTestFile << "</indextestfile>" << endl;
+ kdDebug() << " <icon>" << mIcon << "</icon>" << endl;
+ kdDebug() << " <url>" << mUrl << "</url>" << endl;
+ kdDebug() << " <documenttype>" << mDocumentType << "</documenttype>" << endl;
+ kdDebug() << " </docentry>" << endl;
+}
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/docentry.h b/khelpcenter/docentry.h
new file mode 100644
index 00000000..a2ba6b9c
--- /dev/null
+++ b/khelpcenter/docentry.h
@@ -0,0 +1,117 @@
+#ifndef DOCENTRY_H
+#define DOCENTRY_H
+
+#include <qstring.h>
+#include <qvaluelist.h>
+
+namespace KHC {
+
+class DocEntry
+{
+ public:
+ typedef QValueList<DocEntry *> List;
+
+ DocEntry();
+
+ DocEntry( const QString &name, const QString &url = QString::null,
+ const QString &icon = QString::null );
+
+ void setName( const QString & );
+ QString name() const;
+
+ void setSearch( const QString & );
+ QString search() const;
+
+ void setIcon( const QString & );
+ QString icon() const;
+
+ void setUrl( const QString & );
+ QString url() const;
+
+ void setInfo( const QString & );
+ QString info() const;
+
+ void setLang( const QString & );
+ QString lang() const;
+
+ void setIdentifier( const QString & );
+ QString identifier() const;
+
+ void setIndexer( const QString & );
+ QString indexer() const;
+
+ void setIndexTestFile( const QString & );
+ QString indexTestFile() const;
+
+ void setWeight( int );
+ int weight() const;
+
+ void setSearchMethod( const QString & );
+ QString searchMethod() const;
+
+ void enableSearch( bool enabled );
+ bool searchEnabled() const;
+
+ void setSearchEnabledDefault( bool enabled );
+ bool searchEnabledDefault() const;
+
+ void setDocumentType( const QString & );
+ QString documentType() const;
+
+ void setDirectory( bool );
+ bool isDirectory() const;
+
+ bool readFromFile( const QString &fileName );
+
+ bool indexExists( const QString &indexDir );
+
+ bool docExists() const;
+
+ void addChild( DocEntry * );
+ bool hasChildren();
+ DocEntry *firstChild();
+ List children();
+
+ void setParent( DocEntry * );
+ DocEntry *parent();
+
+ void setNextSibling( DocEntry * );
+ DocEntry *nextSibling();
+
+ QString khelpcenterSpecial() const;
+
+ bool isSearchable();
+
+ void dump() const;
+
+ protected:
+ void init();
+
+ private:
+ QString mName;
+ QString mSearch;
+ QString mIcon;
+ QString mUrl;
+ QString mInfo;
+ QString mLang;
+ mutable QString mIdentifier;
+ QString mIndexer;
+ QString mIndexTestFile;
+ int mWeight;
+ QString mSearchMethod;
+ bool mSearchEnabled;
+ bool mSearchEnabledDefault;
+ QString mDocumentType;
+ bool mDirectory;
+
+ QString mKhelpcenterSpecial;
+
+ List mChildren;
+ DocEntry *mParent;
+ DocEntry *mNextSibling;
+};
+
+}
+
+#endif
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/docentrytraverser.cpp b/khelpcenter/docentrytraverser.cpp
new file mode 100644
index 00000000..d6335d23
--- /dev/null
+++ b/khelpcenter/docentrytraverser.cpp
@@ -0,0 +1,49 @@
+#include "docmetainfo.h"
+
+#include "docentrytraverser.h"
+
+using namespace KHC;
+
+void DocEntryTraverser::setNotifyee( DocMetaInfo *n )
+{
+ mNotifyee = n;
+}
+
+void DocEntryTraverser::startProcess( DocEntry *entry )
+{
+ process( entry );
+ mNotifyee->endProcess( entry, this );
+}
+
+DocEntryTraverser *DocEntryTraverser::childTraverser( DocEntry *parentEntry )
+{
+ DocEntryTraverser *child = createChild( parentEntry );
+ if (!child)
+ return 0;
+ if ( child != this ) {
+ child->mParent = this;
+ child->mNotifyee = mNotifyee;
+ }
+ return child;
+}
+
+DocEntryTraverser *DocEntryTraverser::parentTraverser()
+{
+ return mParent;
+}
+
+void DocEntryTraverser::deleteTraverser()
+{
+ delete this;
+}
+
+void DocEntryTraverser::setParentEntry( DocEntry *entry )
+{
+ mParentEntry = entry;
+}
+
+DocEntry *DocEntryTraverser::parentEntry()
+{
+ return mParentEntry;
+}
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/docentrytraverser.h b/khelpcenter/docentrytraverser.h
new file mode 100644
index 00000000..d8c8cb15
--- /dev/null
+++ b/khelpcenter/docentrytraverser.h
@@ -0,0 +1,44 @@
+#ifndef DOCENTRYTRAVERSER_H
+#define DOCENTRYTRAVERSER_H
+
+namespace KHC {
+
+class DocEntry;
+class DocMetaInfo;
+
+class DocEntryTraverser
+{
+ public:
+ DocEntryTraverser() : mNotifyee( 0 ), mParent( 0 ), mParentEntry( 0 ) {}
+ virtual ~DocEntryTraverser() {}
+
+ void setNotifyee( DocMetaInfo * );
+
+ virtual void process( DocEntry * ) = 0;
+
+ virtual void startProcess( DocEntry * );
+
+ virtual DocEntryTraverser *createChild( DocEntry *parentEntry ) = 0;
+
+ virtual void deleteTraverser();
+
+ virtual void finishTraversal() {}
+
+ DocEntryTraverser *childTraverser( DocEntry *parentEntry );
+ virtual DocEntryTraverser *parentTraverser();
+
+ void setParentEntry( DocEntry * );
+ DocEntry *parentEntry();
+
+ protected:
+ DocMetaInfo *mNotifyee;
+ DocEntryTraverser *mParent;
+
+ private:
+ DocEntry *mParentEntry;
+};
+
+}
+
+#endif
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/docmetainfo.cpp b/khelpcenter/docmetainfo.cpp
new file mode 100644
index 00000000..591d4d4a
--- /dev/null
+++ b/khelpcenter/docmetainfo.cpp
@@ -0,0 +1,287 @@
+#include <qregexp.h>
+
+#include <kdebug.h>
+#include <kstandarddirs.h>
+#include <klocale.h>
+#include <ksimpleconfig.h>
+
+#include "htmlsearch.h"
+
+#include "docentrytraverser.h"
+
+#include "docmetainfo.h"
+
+using namespace KHC;
+
+bool DocMetaInfo::mLoaded = false;
+
+DocMetaInfo *DocMetaInfo::mSelf = 0;
+
+DocMetaInfo *DocMetaInfo::self()
+{
+ if ( !mSelf ) mSelf = new DocMetaInfo;
+ return mSelf;
+}
+
+DocMetaInfo::DocMetaInfo()
+{
+ kdDebug() << "DocMetaInfo()" << endl;
+
+ mHtmlSearch = new HTMLSearch;
+
+ mRootEntry.setName( i18n("Top-Level Documentation") );
+}
+
+DocMetaInfo::~DocMetaInfo()
+{
+ kdDebug() << "~DocMetaInfo()" << endl;
+
+ DocEntry::List::ConstIterator it;
+ for( it = mDocEntries.begin(); it != mDocEntries.end(); ++it ) {
+ delete *it;
+ }
+
+ delete mHtmlSearch;
+
+ mLoaded = false;
+
+ mSelf = 0;
+}
+
+DocEntry *DocMetaInfo::addDocEntry( const QString &fileName )
+{
+ QFileInfo fi( fileName );
+ if ( !fi.exists() ) return 0;
+
+ QString extension = fi.extension();
+ QStringList extensions = QStringList::split( '.', extension );
+ QString lang;
+ if ( extensions.count() >= 2 ) {
+ lang = extensions[ extensions.count() - 2 ];
+ }
+
+ if ( !lang.isEmpty() && mLanguages.find( lang ) == mLanguages.end() ) {
+ return 0;
+ }
+
+ DocEntry *entry = new DocEntry();
+
+ if ( entry->readFromFile( fileName ) ) {
+ if ( !lang.isEmpty() && lang != mLanguages.first() ) {
+ entry->setLang( lang );
+ entry->setName( i18n("doctitle (language)","%1 (%2)")
+ .arg( entry->name() )
+ .arg( mLanguageNames[ lang ] ) );
+ }
+ if ( entry->searchMethod().lower() == "htdig" ) {
+ mHtmlSearch->setupDocEntry( entry );
+ }
+ QString indexer = entry->indexer();
+ indexer.replace( "%f", fileName );
+ entry->setIndexer( indexer );
+ addDocEntry( entry );
+ return entry;
+ } else {
+ delete entry;
+ return 0;
+ }
+}
+
+void DocMetaInfo::addDocEntry( DocEntry *entry )
+{
+ mDocEntries.append( entry );
+ if ( !entry->search().isEmpty() ) mSearchEntries.append( entry );
+}
+
+DocEntry::List DocMetaInfo::docEntries()
+{
+ return mDocEntries;
+}
+
+DocEntry::List DocMetaInfo::searchEntries()
+{
+ return mSearchEntries;
+}
+
+QString DocMetaInfo::languageName( const QString &langcode )
+{
+ if ( langcode == "en" ) return i18n("English");
+
+ QString cfgfile = locate( "locale",
+ QString::fromLatin1( "%1/entry.desktop" ).arg( langcode ) );
+
+ kdDebug() << "-- langcode: " << langcode << " cfgfile: " << cfgfile << endl;
+
+ KSimpleConfig cfg( cfgfile );
+ cfg.setGroup( "KCM Locale" );
+ QString name = cfg.readEntry( "Name", langcode );
+
+ return name;
+}
+
+void DocMetaInfo::scanMetaInfo( bool force )
+{
+ if ( mLoaded && !force ) return;
+
+ mLanguages = KGlobal::locale()->languagesTwoAlpha();
+
+ kdDebug( 1400 ) << "LANGS: " << mLanguages.join( " " ) << endl;
+
+ QStringList::ConstIterator it;
+ for( it = mLanguages.begin(); it != mLanguages.end(); ++it ) {
+ mLanguageNames.insert( *it, languageName( *it ) );
+ }
+
+ KConfig config( "khelpcenterrc" );
+ config.setGroup( "General" );
+ QStringList metaInfos = config.readListEntry( "MetaInfoDirs" );
+
+ if ( metaInfos.isEmpty() ) {
+ KStandardDirs* kstd = KGlobal::dirs();
+ kstd->addResourceType( "data", "share/apps/khelpcenter" );
+ metaInfos = kstd->findDirs( "data", "plugins" );
+ }
+ for( it = metaInfos.begin(); it != metaInfos.end(); it++) {
+ kdDebug() << "DocMetaInfo::scanMetaInfo(): scanning " << *it << endl;
+ scanMetaInfoDir( *it, &mRootEntry );
+ }
+
+ mLoaded = true;
+}
+
+DocEntry *DocMetaInfo::scanMetaInfoDir( const QString &dirName,
+ DocEntry *parent )
+{
+ QDir dir( dirName );
+ if ( !dir.exists() ) return 0;
+
+ const QFileInfoList *entryList = dir.entryInfoList();
+ QFileInfoListIterator it( *entryList );
+ QFileInfo *fi;
+ for( ; ( fi = it.current() ); ++it ) {
+ DocEntry *entry = 0;
+ if ( fi->isDir() && fi->fileName() != "." && fi->fileName() != ".." ) {
+ DocEntry *dirEntry = addDirEntry( QDir( fi->absFilePath() ), parent );
+ entry = scanMetaInfoDir( fi->absFilePath(), dirEntry );
+ } else if ( fi->extension( false ) == "desktop" ) {
+ entry = addDocEntry( fi->absFilePath() );
+ if ( parent && entry ) parent->addChild( entry );
+ }
+ }
+
+ return 0;
+}
+
+DocEntry *DocMetaInfo::addDirEntry( const QDir &dir, DocEntry *parent )
+{
+ DocEntry *dirEntry = addDocEntry( dir.absPath() + "/.directory" );
+
+ if ( !dirEntry ) {
+ dirEntry = new DocEntry;
+ dirEntry->setName( dir.dirName() );
+ addDocEntry( dirEntry );
+ }
+
+ dirEntry->setDirectory( true );
+
+ if ( parent ) parent->addChild( dirEntry );
+
+ return dirEntry;
+}
+
+
+void DocMetaInfo::traverseEntries( DocEntryTraverser *traverser )
+{
+ traverseEntry( &mRootEntry, traverser );
+}
+
+void DocMetaInfo::traverseEntry( DocEntry *entry, DocEntryTraverser *traverser )
+{
+ DocEntry::List children = entry->children();
+ DocEntry::List::ConstIterator it;
+ for( it = children.begin(); it != children.end(); ++it ) {
+ if ( (*it)->isDirectory() && !(*it)->hasChildren() &&
+ (*it)->khelpcenterSpecial().isEmpty() ) continue;
+ traverser->process( *it );
+ if ( (*it)->hasChildren() ) {
+ DocEntryTraverser *t = traverser->childTraverser( *it );
+ if (t) {
+ traverseEntry( *it, t );
+ t->deleteTraverser();
+ }
+ }
+ }
+}
+
+void DocMetaInfo::startTraverseEntries( DocEntryTraverser *traverser )
+{
+ kdDebug() << "DocMetaInfo::startTraverseEntries()" << endl;
+ traverser->setNotifyee( this );
+ startTraverseEntry( &mRootEntry, traverser );
+}
+
+void DocMetaInfo::startTraverseEntry( DocEntry *entry,
+ DocEntryTraverser *traverser )
+{
+// kdDebug() << "DocMetaInfo::startTraverseEntry() " << entry->name() << endl;
+
+ if ( !traverser ) {
+ kdDebug() << "DocMetaInfo::startTraverseEntry(): ERROR. No Traverser."
+ << endl;
+ return;
+ }
+
+ if ( !entry ) {
+ kdDebug() << "DocMetaInfo::startTraverseEntry(): no entry." << endl;
+ endTraverseEntries( traverser );
+ return;
+ }
+
+ traverser->startProcess( entry );
+}
+
+void DocMetaInfo::endProcess( DocEntry *entry, DocEntryTraverser *traverser )
+{
+// kdDebug() << "DocMetaInfo::endProcess() " << entry->name() << endl;
+
+ if ( !entry ) {
+ endTraverseEntries( traverser );
+ return;
+ }
+
+ if ( entry->hasChildren() ) {
+ startTraverseEntry( entry->firstChild(), traverser->childTraverser( entry ) );
+ } else if ( entry->nextSibling() ) {
+ startTraverseEntry( entry->nextSibling(), traverser );
+ } else {
+ DocEntry *parent = entry->parent();
+ DocEntryTraverser *parentTraverser = 0;
+ while ( parent ) {
+ parentTraverser = traverser->parentTraverser();
+ traverser->deleteTraverser();
+ if ( parent->nextSibling() ) {
+ startTraverseEntry( parent->nextSibling(), parentTraverser );
+ break;
+ } else {
+ parent = parent->parent();
+ traverser = parentTraverser;
+ }
+ }
+ if ( !parent ) {
+ endTraverseEntries( traverser );
+ }
+ }
+}
+
+void DocMetaInfo::endTraverseEntries( DocEntryTraverser *traverser )
+{
+ kdDebug() << "DocMetaInfo::endTraverseEntries()" << endl;
+
+ if ( !traverser ) {
+ kdDebug() << " no more traversers." << endl;
+ return;
+ }
+
+ traverser->finishTraversal();
+}
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/docmetainfo.h b/khelpcenter/docmetainfo.h
new file mode 100644
index 00000000..fbca6079
--- /dev/null
+++ b/khelpcenter/docmetainfo.h
@@ -0,0 +1,80 @@
+#ifndef DOCMETAINFO_H
+#define DOCMETAINFO_H
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qvaluelist.h>
+#include <qdir.h>
+#include <qmap.h>
+
+#include "docentry.h"
+
+namespace KHC {
+
+class HTMLSearch;
+class DocEntryTraverser;
+
+/*!
+ This class provides some meta information about help documents.
+*/
+class DocMetaInfo
+{
+ public:
+ /*!
+ Return instance of DocMetaInfo. There can only be one instance at a time.
+ */
+ static DocMetaInfo *self();
+
+ ~DocMetaInfo();
+
+ void scanMetaInfo( bool force = false );
+
+ DocEntry *addDocEntry( const QString &fileName );
+
+ void addDocEntry( DocEntry * );
+
+ DocEntry::List docEntries();
+
+ DocEntry::List searchEntries();
+
+ void traverseEntries( DocEntryTraverser * );
+
+ void startTraverseEntries( DocEntryTraverser *traverser );
+ void startTraverseEntry( DocEntry *entry, DocEntryTraverser *traverser );
+ void endProcess( DocEntry *entry, DocEntryTraverser *traverser );
+ void endTraverseEntries( DocEntryTraverser * );
+
+ static QString languageName( const QString &langcode );
+
+ protected:
+ DocEntry *scanMetaInfoDir( const QString &filename, DocEntry *parent );
+ DocEntry *addDirEntry( const QDir &dir, DocEntry *parent );
+ void traverseEntry( DocEntry *, DocEntryTraverser * );
+
+ private:
+ /*!
+ DocMetaInfo is a singleton. Private constructor prevents direct
+ instantisation.
+ */
+ DocMetaInfo();
+
+ DocEntry::List mDocEntries;
+ DocEntry::List mSearchEntries;
+
+ DocEntry mRootEntry;
+
+ QStringList mLanguages;
+
+ QMap<QString,QString> mLanguageNames;
+
+ HTMLSearch *mHtmlSearch;
+
+ static bool mLoaded;
+
+ static DocMetaInfo *mSelf;
+};
+
+}
+
+#endif
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/fontdialog.cpp b/khelpcenter/fontdialog.cpp
new file mode 100644
index 00000000..fb7b5e52
--- /dev/null
+++ b/khelpcenter/fontdialog.cpp
@@ -0,0 +1,212 @@
+/*
+ * This file is part of the KDE Help Center
+ *
+ * Copyright (C) 2003 Frerich Raabe <raabe@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "fontdialog.h"
+
+#include <kapplication.h>
+#include <kcharsets.h>
+#include <kcombobox.h>
+#include <kconfig.h>
+#include <kfontcombo.h>
+#include <khtmldefaults.h>
+#include <klocale.h>
+#include <knuminput.h>
+
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qspinbox.h>
+
+using namespace KHC;
+
+FontDialog::FontDialog( QWidget *parent, const char *name )
+ : KDialogBase( parent, name, true, i18n( "Font Configuration" ),
+ Ok | Cancel )
+{
+ makeVBoxMainWidget();
+
+ setupFontSizesBox();
+ setupFontTypesBox();
+ setupFontEncodingBox();
+
+ load();
+}
+
+void FontDialog::slotOk()
+{
+ save();
+ accept();
+}
+
+void FontDialog::setupFontSizesBox()
+{
+ QGroupBox *gb = new QGroupBox( i18n( "Sizes" ), mainWidget() );
+
+ QGridLayout *layout = new QGridLayout( gb );
+ layout->setSpacing( KDialog::spacingHint() );
+ layout->setMargin( KDialog::marginHint() * 2 );
+
+ QLabel *lMinFontSize = new QLabel( i18n( "M&inimum font size:" ), gb );
+ layout->addWidget( lMinFontSize, 0, 0 );
+ m_minFontSize = new KIntNumInput( gb );
+ layout->addWidget( m_minFontSize, 0, 1 );
+ m_minFontSize->setRange( 1, 20 );
+ lMinFontSize->setBuddy( m_minFontSize );
+
+ QLabel *lMedFontSize = new QLabel( i18n( "M&edium font size:" ), gb );
+ layout->addWidget( lMedFontSize, 1, 0 );
+ m_medFontSize = new KIntNumInput( gb );
+ layout->addWidget( m_medFontSize, 1, 1 );
+ m_medFontSize->setRange( 4, 28 );
+ lMedFontSize->setBuddy( m_medFontSize );
+}
+
+void FontDialog::setupFontTypesBox()
+{
+ QGroupBox *gb = new QGroupBox( i18n( "Fonts" ), mainWidget() );
+
+ QGridLayout *layout = new QGridLayout( gb );
+ layout->setSpacing( KDialog::spacingHint() );
+ layout->setMargin( KDialog::marginHint() * 2 );
+
+ QLabel *lStandardFont = new QLabel( i18n( "S&tandard font:" ), gb );
+ layout->addWidget( lStandardFont, 0, 0 );
+ m_standardFontCombo = new KFontCombo( gb );
+ layout->addWidget( m_standardFontCombo, 0, 1 );
+ lStandardFont->setBuddy( m_standardFontCombo );
+
+ QLabel *lFixedFont = new QLabel( i18n( "F&ixed font:" ), gb );
+ layout->addWidget( lFixedFont, 1, 0 );
+ m_fixedFontCombo = new KFontCombo( gb );
+ layout->addWidget( m_fixedFontCombo, 1, 1 );
+ lFixedFont->setBuddy( m_fixedFontCombo );
+
+ QLabel *lSerifFont = new QLabel( i18n( "S&erif font:" ), gb );
+ layout->addWidget( lSerifFont, 2, 0 );
+ m_serifFontCombo = new KFontCombo( gb );
+ layout->addWidget( m_serifFontCombo, 2, 1 );
+ lSerifFont->setBuddy( m_serifFontCombo );
+
+ QLabel *lSansSerifFont = new QLabel( i18n( "S&ans serif font:" ), gb );
+ layout->addWidget( lSansSerifFont, 3, 0 );
+ m_sansSerifFontCombo = new KFontCombo( gb );
+ layout->addWidget( m_sansSerifFontCombo, 3, 1 );
+ lSansSerifFont->setBuddy( m_sansSerifFontCombo );
+
+ QLabel *lItalicFont = new QLabel( i18n( "&Italic font:" ), gb );
+ layout->addWidget( lItalicFont, 4, 0 );
+ m_italicFontCombo = new KFontCombo( gb );
+ layout->addWidget( m_italicFontCombo, 4, 1 );
+ lItalicFont->setBuddy( m_italicFontCombo );
+
+ QLabel *lFantasyFont = new QLabel( i18n( "&Fantasy font:" ), gb );
+ layout->addWidget( lFantasyFont, 5, 0 );
+ m_fantasyFontCombo = new KFontCombo( gb );
+ layout->addWidget( m_fantasyFontCombo, 5, 1 );
+ lFantasyFont->setBuddy( m_fantasyFontCombo );
+}
+
+void FontDialog::setupFontEncodingBox()
+{
+ QGroupBox *gb = new QGroupBox( i18n( "Encoding" ), mainWidget() );
+
+ QGridLayout *layout = new QGridLayout( gb );
+ layout->setSpacing( KDialog::spacingHint() );
+ layout->setMargin( KDialog::marginHint() * 2 );
+
+ QLabel *lDefaultEncoding = new QLabel( i18n( "&Default encoding:" ), gb );
+ layout->addWidget( lDefaultEncoding, 0, 0 );
+ m_defaultEncoding = new KComboBox( false, gb );
+ layout->addWidget( m_defaultEncoding, 0, 1 );
+ QStringList encodings = KGlobal::charsets()->availableEncodingNames();
+ encodings.prepend( i18n( "Use Language Encoding" ) );
+ m_defaultEncoding->insertStringList( encodings );
+ lDefaultEncoding->setBuddy( m_defaultEncoding );
+
+ QLabel *lFontSizeAdjustement = new QLabel( i18n( "&Font size adjustment:" ), gb );
+ layout->addWidget( lFontSizeAdjustement, 1, 0 );
+ m_fontSizeAdjustement = new QSpinBox( -5, 5, 1, gb );
+ layout->addWidget( m_fontSizeAdjustement, 1, 1 );
+ lFontSizeAdjustement->setBuddy( m_fontSizeAdjustement );
+}
+
+void FontDialog::load()
+{
+ KConfig *cfg = kapp->config();
+ {
+ KConfigGroupSaver groupSaver( cfg, "HTML Settings" );
+
+ m_minFontSize->setValue( cfg->readNumEntry( "MinimumFontSize", HTML_DEFAULT_MIN_FONT_SIZE ) );
+ m_medFontSize->setValue( cfg->readNumEntry( "MediumFontSize", 10 ) );
+
+ QStringList fonts = cfg->readListEntry( "Fonts" );
+ if ( fonts.isEmpty() )
+ fonts << KGlobalSettings::generalFont().family()
+ << KGlobalSettings::fixedFont().family()
+ << HTML_DEFAULT_VIEW_SERIF_FONT
+ << HTML_DEFAULT_VIEW_SANSSERIF_FONT
+ << HTML_DEFAULT_VIEW_CURSIVE_FONT
+ << HTML_DEFAULT_VIEW_FANTASY_FONT;
+
+ m_standardFontCombo->setCurrentFont( fonts[ 0 ] );
+ m_fixedFontCombo->setCurrentFont( fonts[ 1 ] );
+ m_serifFontCombo->setCurrentFont( fonts[ 2 ] );
+ m_sansSerifFontCombo->setCurrentFont( fonts[ 3 ] );
+ m_italicFontCombo->setCurrentFont( fonts[ 4 ] );
+ m_fantasyFontCombo->setCurrentFont( fonts[ 5 ] );
+
+ m_defaultEncoding->setCurrentItem( cfg->readEntry( "DefaultEncoding" ) );
+ m_fontSizeAdjustement->setValue( fonts[ 6 ].toInt() );
+ }
+}
+
+void FontDialog::save()
+{
+ KConfig *cfg = kapp->config();
+ {
+ KConfigGroupSaver groupSaver( cfg, "General" );
+ cfg->writeEntry( "UseKonqSettings", false );
+ }
+ {
+ KConfigGroupSaver groupSaver( cfg, "HTML Settings" );
+
+ cfg->writeEntry( "MinimumFontSize", m_minFontSize->value() );
+ cfg->writeEntry( "MediumFontSize", m_medFontSize->value() );
+
+ QStringList fonts;
+ fonts << m_standardFontCombo->currentText()
+ << m_fixedFontCombo->currentText()
+ << m_serifFontCombo->currentText()
+ << m_sansSerifFontCombo->currentText()
+ << m_italicFontCombo->currentText()
+ << m_fantasyFontCombo->currentText()
+ << QString::number( m_fontSizeAdjustement->value() );
+
+ cfg->writeEntry( "Fonts", fonts );
+
+ if ( m_defaultEncoding->currentText() == i18n( "Use Language Encoding" ) )
+ cfg->writeEntry( "DefaultEncoding", QString::null );
+ else
+ cfg->writeEntry( "DefaultEncoding", m_defaultEncoding->currentText() );
+ }
+ cfg->sync();
+}
+
+#include "fontdialog.moc"
+// vim:ts=4:sw=4:noet
diff --git a/khelpcenter/fontdialog.h b/khelpcenter/fontdialog.h
new file mode 100644
index 00000000..fc468cd2
--- /dev/null
+++ b/khelpcenter/fontdialog.h
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the KDE Help Center
+ *
+ * Copyright (C) 2003 Frerich Raabe <raabe@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef FONTDIALOG_H
+#define FONTDIALOG_H
+
+#include <kdialogbase.h>
+
+class QBoxLayout;
+class QSpinBox;
+
+class KComboBox;
+class KFontCombo;
+class KIntNumInput;
+
+namespace KHC {
+
+class FontDialog : public KDialogBase
+{
+ Q_OBJECT
+ public:
+ FontDialog( QWidget *parent, const char *name = 0 );
+
+ protected slots:
+ virtual void slotOk();
+
+ private:
+ void setupFontSizesBox();
+ void setupFontTypesBox();
+ void setupFontEncodingBox();
+
+ void load();
+ void save();
+
+ KIntNumInput *m_minFontSize;
+ KIntNumInput *m_medFontSize;
+ KFontCombo *m_standardFontCombo;
+ KFontCombo *m_fixedFontCombo;
+ KFontCombo *m_serifFontCombo;
+ KFontCombo *m_sansSerifFontCombo;
+ KFontCombo *m_italicFontCombo;
+ KFontCombo *m_fantasyFontCombo;
+ KComboBox *m_defaultEncoding;
+ QSpinBox *m_fontSizeAdjustement;
+};
+
+}
+
+#endif // FONTDIALOG_H
+// vim:ts=4:sw=4:noet
diff --git a/khelpcenter/formatter.cpp b/khelpcenter/formatter.cpp
new file mode 100644
index 00000000..e31c9d43
--- /dev/null
+++ b/khelpcenter/formatter.cpp
@@ -0,0 +1,222 @@
+/*
+ This file is part of KHelpcenter.
+
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include "formatter.h"
+
+#include <klocale.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <kconfig.h>
+#include <kstandarddirs.h>
+
+#include <qfile.h>
+#include <qtextstream.h>
+
+using namespace KHC;
+
+Formatter::Formatter()
+ : mHasTemplate( false )
+{
+}
+
+Formatter:: ~Formatter()
+{
+}
+
+bool Formatter::readTemplates()
+{
+ KConfig *cfg = KGlobal::config();
+ cfg->setGroup( "Templates" );
+ QString mainTemplate = cfg->readEntry( "MainTemplate" );
+
+ if ( mainTemplate.isEmpty() ) {
+ mainTemplate = locate( "appdata", "maintemplate" );
+ }
+
+ if ( mainTemplate.isEmpty() ) {
+ kdWarning() << "Main template file name is empty." << endl;
+ return false;
+ }
+
+ QFile f( mainTemplate );
+ if ( !f.open( IO_ReadOnly ) ) {
+ kdWarning() << "Unable to open main template file '" << mainTemplate
+ << "'." << endl;
+ return false;
+ }
+
+ QTextStream ts( &f );
+ QString line;
+ enum State { IDLE, SINGLELINE, MULTILINE };
+ State state = IDLE;
+ QString symbol;
+ QString endMarker;
+ QString value;
+ while( !( line = ts.readLine() ).isNull() ) {
+ switch ( state ) {
+ case IDLE:
+ if ( !line.isEmpty() && !line.startsWith( "#" ) ) {
+ int pos = line.find( "<<" );
+ if ( pos >= 0 ) {
+ state = MULTILINE;
+ symbol = line.left( pos ).stripWhiteSpace();
+ endMarker = line.mid( pos + 2 ).stripWhiteSpace();
+ } else {
+ state = SINGLELINE;
+ symbol = line.stripWhiteSpace();
+ }
+ }
+ break;
+ case SINGLELINE:
+ mSymbols.insert( symbol, line );
+ state = IDLE;
+ break;
+ case MULTILINE:
+ if ( line.startsWith( endMarker ) ) {
+ mSymbols.insert( symbol, value );
+ value = "";
+ state = IDLE;
+ } else {
+ value += line + '\n';
+ }
+ break;
+ default:
+ kdError() << "Formatter::readTemplates(): Illegal state: "
+ << state << endl;
+ break;
+ }
+ }
+
+ f.close();
+
+#if 0
+ QMap<QString,QString>::ConstIterator it;
+ for( it = mSymbols.begin(); it != mSymbols.end(); ++it ) {
+ kdDebug() << "KEY: " << it.key() << endl;
+ kdDebug() << "VALUE: " << it.data() << endl;
+ }
+#endif
+
+ QStringList requiredSymbols;
+ requiredSymbols << "HEADER" << "FOOTER";
+
+ bool success = true;
+ QStringList::ConstIterator it2;
+ for( it2 = requiredSymbols.begin(); it2 != requiredSymbols.end(); ++it2 ) {
+ if ( !mSymbols.contains( *it2 ) ) {
+ success = false;
+ kdError() << "Symbol '" << *it2 << "' is missing from main template file."
+ << endl;
+ }
+ }
+
+ if ( success ) mHasTemplate = true;
+
+ return success;
+}
+
+QString Formatter::header( const QString &title )
+{
+ QString s;
+ if ( mHasTemplate ) {
+ s = mSymbols[ "HEADER" ];
+ s.replace( "--TITLE:--", title );
+ } else {
+ s = "<html><head><title>" + title + "</title></head>\n<body>\n";
+ }
+ return s;
+}
+
+QString Formatter::footer()
+{
+ if ( mHasTemplate ) {
+ return mSymbols[ "FOOTER" ];
+ } else {
+ return "</body></html>";
+ }
+}
+
+QString Formatter::separator()
+{
+// return "<table width=100%><tr><td bgcolor=\"#7B8962\">&nbsp;"
+// "</td></tr></table>";
+ return "<hr>";
+}
+
+QString Formatter::docTitle( const QString &title )
+{
+ return "<h3><font color=\"red\">" + title + "</font></h3>";
+}
+
+QString Formatter::sectionHeader( const QString &section )
+{
+ return "<h2><font color=\"blue\">" + section + "</font></h2>";
+}
+
+QString Formatter::processResult( const QString &data )
+{
+ QString result;
+
+ enum { Header, BodyTag, Body, Footer };
+
+ int state = Header;
+
+ for( uint i = 0; i < data.length(); ++i ) {
+ QChar c = data[i];
+ switch ( state ) {
+ case Header:
+ if ( c == '<' && data.mid( i, 5 ).lower() == "<body" ) {
+ state = BodyTag;
+ i += 4;
+ }
+ break;
+ case BodyTag:
+ if ( c == '>' ) state = Body;
+ break;
+ case Body:
+ if ( c == '<' && data.mid( i, 7 ).lower() == "</body>" ) {
+ state = Footer;
+ } else {
+ result.append( c );
+ }
+ break;
+ case Footer:
+ break;
+ default:
+ result.append( c );
+ break;
+ }
+ }
+
+ if ( state == Header ) return data;
+ else return result;
+}
+
+QString Formatter::paragraph( const QString &str )
+{
+ return "<p>" + str + "</p>";
+}
+
+QString Formatter::title( const QString &title )
+{
+ return "<h2>" + title + "</h2>";
+}
+
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/formatter.h b/khelpcenter/formatter.h
new file mode 100644
index 00000000..97e03c17
--- /dev/null
+++ b/khelpcenter/formatter.h
@@ -0,0 +1,55 @@
+/*
+ This file is part of KHelpcenter.
+
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+#ifndef KHC_FORMATTER_H
+#define KHC_FORMATTER_H
+
+#include <qstring.h>
+#include <qmap.h>
+
+namespace KHC {
+
+class Formatter
+{
+ public:
+ Formatter();
+ virtual ~Formatter();
+
+ bool readTemplates();
+
+ virtual QString header( const QString &title );
+ virtual QString footer();
+ virtual QString separator();
+ virtual QString docTitle( const QString & );
+ virtual QString sectionHeader( const QString & );
+ virtual QString paragraph( const QString & );
+ virtual QString title( const QString & );
+
+ virtual QString processResult( const QString & );
+
+ private:
+ bool mHasTemplate;
+ QMap<QString,QString> mSymbols;
+};
+
+}
+
+#endif
+
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/glossary.cpp b/khelpcenter/glossary.cpp
new file mode 100644
index 00000000..6d19aac5
--- /dev/null
+++ b/khelpcenter/glossary.cpp
@@ -0,0 +1,322 @@
+/*
+ * This file is part of the KDE Help Center
+ *
+ * Copyright (C) 2002 Frerich Raabe (raabe@kde.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "glossary.h"
+#include "view.h"
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kmainwindow.h>
+#include <kprocess.h>
+#include <kstandarddirs.h>
+#include <kstatusbar.h>
+
+#include <qheader.h>
+
+#include <sys/stat.h>
+
+using namespace KHC;
+
+class SectionItem : public KListViewItem
+{
+ public:
+ SectionItem( QListViewItem *parent, const QString &text )
+ : KListViewItem( parent, text )
+ {
+ setOpen( false );
+ }
+
+ virtual void setOpen( bool open )
+ {
+ KListViewItem::setOpen(open);
+
+ setPixmap( 0, SmallIcon( QString::fromLatin1( open ? "contents" : "contents2" ) ) );
+
+ }
+};
+
+class EntryItem : public KListViewItem
+{
+ public:
+ EntryItem( SectionItem *parent, const QString &term, const QString &id )
+ : KListViewItem( parent, term ),
+ m_id( id )
+ {
+ }
+
+ QString id() const { return m_id; }
+
+ private:
+ QString m_id;
+};
+
+Glossary::Glossary( QWidget *parent ) : KListView( parent )
+{
+ m_initialized = false;
+
+ connect( this, SIGNAL( clicked( QListViewItem * ) ),
+ this, SLOT( treeItemSelected( QListViewItem * ) ) );
+ connect( this, SIGNAL( returnPressed( QListViewItem * ) ),
+ this, SLOT( treeItemSelected( QListViewItem * ) ) );
+
+ setFrameStyle( QFrame::Panel | QFrame::Sunken );
+ addColumn( QString::null );
+ header()->hide();
+ setAllColumnsShowFocus( true );
+ setRootIsDecorated( true );
+
+ m_byTopicItem = new KListViewItem( this, i18n( "By Topic" ) );
+ m_byTopicItem->setPixmap( 0, SmallIcon( "help" ) );
+
+ m_alphabItem = new KListViewItem( this, i18n( "Alphabetically" ) );
+ m_alphabItem->setPixmap( 0, SmallIcon( "charset" ) );
+
+ m_cacheFile = locateLocal( "cache", "help/glossary.xml" );
+
+ m_sourceFile = View::View::langLookup( QString::fromLatin1( "khelpcenter/glossary/index.docbook" ) );
+
+ m_config = kapp->config();
+ m_config->setGroup( "Glossary" );
+
+}
+
+void Glossary::show()
+{
+ if ( !m_initialized ) {
+ if ( cacheStatus() == NeedRebuild )
+ rebuildGlossaryCache();
+ else
+ buildGlossaryTree();
+ m_initialized = true;
+ }
+ KListView::show();
+}
+
+Glossary::~Glossary()
+{
+ m_glossEntries.setAutoDelete( true );
+ m_glossEntries.clear();
+}
+
+const GlossaryEntry &Glossary::entry( const QString &id ) const
+{
+ return *m_glossEntries[ id ];
+}
+
+Glossary::CacheStatus Glossary::cacheStatus() const
+{
+ if ( !QFile::exists( m_cacheFile ) ||
+ m_config->readPathEntry( "CachedGlossary" ) != m_sourceFile ||
+ m_config->readNumEntry( "CachedGlossaryTimestamp" ) != glossaryCTime() )
+ return NeedRebuild;
+
+ return CacheOk;
+}
+
+int Glossary::glossaryCTime() const
+{
+ struct stat stat_buf;
+ stat( QFile::encodeName( m_sourceFile ).data(), &stat_buf );
+
+ return stat_buf.st_ctime;
+}
+
+void Glossary::rebuildGlossaryCache()
+{
+ KMainWindow *mainWindow = dynamic_cast<KMainWindow *>( kapp->mainWidget() );
+ Q_ASSERT( mainWindow );
+ mainWindow->statusBar()->message( i18n( "Rebuilding cache..." ) );
+
+ KProcess *meinproc = new KProcess;
+ connect( meinproc, SIGNAL( processExited( KProcess * ) ),
+ this, SLOT( meinprocExited( KProcess * ) ) );
+
+ *meinproc << locate( "exe", QString::fromLatin1( "meinproc" ) );
+ *meinproc << QString::fromLatin1( "--output" ) << m_cacheFile;
+ *meinproc << QString::fromLatin1( "--stylesheet" )
+ << locate( "data", QString::fromLatin1( "khelpcenter/glossary.xslt" ) );
+ *meinproc << m_sourceFile;
+
+ meinproc->start( KProcess::NotifyOnExit );
+}
+
+void Glossary::meinprocExited( KProcess *meinproc )
+{
+ delete meinproc;
+
+ if ( !QFile::exists( m_cacheFile ) )
+ return;
+
+ m_config->writePathEntry( "CachedGlossary", m_sourceFile );
+ m_config->writeEntry( "CachedGlossaryTimestamp", glossaryCTime() );
+ m_config->sync();
+
+ m_status = CacheOk;
+
+ KMainWindow *mainWindow = dynamic_cast<KMainWindow *>( kapp->mainWidget() );
+ Q_ASSERT( mainWindow );
+ mainWindow->statusBar()->message( i18n( "Rebuilding cache... done." ), 2000 );
+
+ buildGlossaryTree();
+}
+
+void Glossary::buildGlossaryTree()
+{
+ QFile cacheFile(m_cacheFile);
+ if ( !cacheFile.open( IO_ReadOnly ) )
+ return;
+
+ QDomDocument doc;
+ if ( !doc.setContent( &cacheFile ) )
+ return;
+
+ QDomNodeList sectionNodes = doc.documentElement().elementsByTagName( QString::fromLatin1( "section" ) );
+ for ( unsigned int i = 0; i < sectionNodes.count(); i++ ) {
+ QDomElement sectionElement = sectionNodes.item( i ).toElement();
+ QString title = sectionElement.attribute( QString::fromLatin1( "title" ) );
+ SectionItem *topicSection = new SectionItem( m_byTopicItem, title );
+
+ QDomNodeList entryNodes = sectionElement.elementsByTagName( QString::fromLatin1( "entry" ) );
+ for ( unsigned int j = 0; j < entryNodes.count(); j++ ) {
+ QDomElement entryElement = entryNodes.item( j ).toElement();
+
+ QString entryId = entryElement.attribute( QString::fromLatin1( "id" ) );
+ if ( entryId.isNull() )
+ continue;
+
+ QDomElement termElement = childElement( entryElement, QString::fromLatin1( "term" ) );
+ QString term = termElement.text().simplifyWhiteSpace();
+
+ EntryItem *entry = new EntryItem(topicSection, term, entryId );
+ m_idDict.insert( entryId, entry );
+
+ SectionItem *alphabSection = 0L;
+ for ( QListViewItemIterator it( m_alphabItem ); it.current(); it++ )
+ if ( it.current()->text( 0 ) == term[ 0 ].upper() ) {
+ alphabSection = static_cast<SectionItem *>( it.current() );
+ break;
+ }
+
+ if ( !alphabSection )
+ alphabSection = new SectionItem( m_alphabItem, term[ 0 ].upper() );
+
+ new EntryItem( alphabSection, term, entryId );
+
+ QDomElement definitionElement = childElement( entryElement, QString::fromLatin1( "definition" ) );
+ QString definition = definitionElement.text().simplifyWhiteSpace();
+
+ GlossaryEntryXRef::List seeAlso;
+
+ QDomElement referencesElement = childElement( entryElement, QString::fromLatin1( "references" ) );
+ QDomNodeList referenceNodes = referencesElement.elementsByTagName( QString::fromLatin1( "reference" ) );
+ if ( referenceNodes.count() > 0 )
+ for ( unsigned int k = 0; k < referenceNodes.count(); k++ ) {
+ QDomElement referenceElement = referenceNodes.item( k ).toElement();
+
+ QString term = referenceElement.attribute( QString::fromLatin1( "term" ) );
+ QString id = referenceElement.attribute( QString::fromLatin1( "id" ) );
+
+ seeAlso += GlossaryEntryXRef( term, id );
+ }
+
+ m_glossEntries.insert( entryId, new GlossaryEntry( term, definition, seeAlso ) );
+ }
+ }
+}
+
+void Glossary::treeItemSelected( QListViewItem *item )
+{
+ if ( !item )
+ return;
+
+ if ( EntryItem *i = dynamic_cast<EntryItem *>( item ) )
+ emit entrySelected( entry( i->id() ) );
+
+ item->setOpen( !item->isOpen() );
+}
+
+QDomElement Glossary::childElement( const QDomElement &element, const QString &name )
+{
+ QDomElement e;
+ for ( e = element.firstChild().toElement(); !e.isNull(); e = e.nextSibling().toElement() )
+ if ( e.tagName() == name )
+ break;
+ return e;
+}
+
+QString Glossary::entryToHtml( const GlossaryEntry &entry )
+{
+ QFile htmlFile( locate("data", "khelpcenter/glossary.html.in" ) );
+ if (!htmlFile.open(IO_ReadOnly))
+ return QString( "<html><head></head><body><h3>%1</h3>%2</body></html>" )
+ .arg( i18n( "Error" ) )
+ .arg( i18n( "Unable to show selected glossary entry: unable to open "
+ "file 'glossary.html.in'!" ) );
+
+ QString seeAlso;
+ if (!entry.seeAlso().isEmpty()) {
+ seeAlso = i18n("See also: ");
+ GlossaryEntryXRef::List seeAlsos = entry.seeAlso();
+ GlossaryEntryXRef::List::ConstIterator it = seeAlsos.begin();
+ GlossaryEntryXRef::List::ConstIterator end = seeAlsos.end();
+ for (; it != end; ++it) {
+ seeAlso += QString::fromLatin1("<a href=\"glossentry:");
+ seeAlso += (*it).id();
+ seeAlso += QString::fromLatin1("\">") + (*it).term();
+ seeAlso += QString::fromLatin1("</a>, ");
+ }
+ seeAlso = seeAlso.left(seeAlso.length() - 2);
+ }
+
+ QTextStream htmlStream(&htmlFile);
+ return htmlStream.read()
+ .arg( i18n( "KDE Glossary" ) )
+ .arg( entry.term() )
+ .arg( View::langLookup( "khelpcenter/konq.css" ) )
+ .arg( View::langLookup( "khelpcenter/pointers.png" ) )
+ .arg( View::langLookup( "khelpcenter/khelpcenter.png" ) )
+ .arg( View::langLookup( "khelpcenter/lines.png" ) )
+ .arg( entry.term() )
+ .arg( entry.definition() )
+ .arg( seeAlso)
+ .arg( View::langLookup( "khelpcenter/kdelogo2.png" ) );
+}
+
+void Glossary::slotSelectGlossEntry( const QString &id )
+{
+ EntryItem *newItem = m_idDict.find( id );
+ if ( newItem == 0 )
+ return;
+
+ EntryItem *curItem = dynamic_cast<EntryItem *>( currentItem() );
+ if ( curItem != 0 ) {
+ if ( curItem->id() == id )
+ return;
+ curItem->parent()->setOpen( false );
+ }
+
+ setCurrentItem( newItem );
+ ensureItemVisible( newItem );
+}
+
+#include "glossary.moc"
+// vim:ts=4:sw=4:et
diff --git a/khelpcenter/glossary.h b/khelpcenter/glossary.h
new file mode 100644
index 00000000..56a4425c
--- /dev/null
+++ b/khelpcenter/glossary.h
@@ -0,0 +1,146 @@
+/*
+ * glossary.h - part of the KDE Help Center
+ *
+ * Copyright (C) 2002 Frerich Raabe (raabe@kde.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef KHC_GLOSSARY_H
+#define KHC_GLOSSARY_H
+
+#include <klistview.h>
+
+#include <qdict.h>
+#include <qdom.h>
+#include <qstringlist.h>
+
+class KConfig;
+class KProcess;
+
+class EntryItem;
+
+namespace KHC {
+
+class GlossaryEntryXRef
+{
+ friend QDataStream &operator>>( QDataStream &, GlossaryEntryXRef & );
+ public:
+ typedef QValueList<GlossaryEntryXRef> List;
+
+ GlossaryEntryXRef() {}
+ GlossaryEntryXRef( const QString &term, const QString &id ) :
+ m_term( term ),
+ m_id( id )
+ {
+ }
+
+ QString term() const { return m_term; }
+ QString id() const { return m_id; }
+
+ private:
+ QString m_term;
+ QString m_id;
+};
+
+inline QDataStream &operator<<( QDataStream &stream, const GlossaryEntryXRef &e )
+{
+ return stream << e.term() << e.id();
+}
+
+inline QDataStream &operator>>( QDataStream &stream, GlossaryEntryXRef &e )
+{
+ return stream >> e.m_term >> e.m_id;
+}
+
+class GlossaryEntry
+{
+ friend QDataStream &operator>>( QDataStream &, GlossaryEntry & );
+ public:
+ GlossaryEntry() {}
+ GlossaryEntry( const QString &term, const QString &definition,
+ const GlossaryEntryXRef::List &seeAlso ) :
+ m_term( term ),
+ m_definition( definition ),
+ m_seeAlso( seeAlso )
+ {
+ }
+
+ QString term() const { return m_term; }
+ QString definition() const { return m_definition; }
+ GlossaryEntryXRef::List seeAlso() const { return m_seeAlso; }
+
+ private:
+ QString m_term;
+ QString m_definition;
+ GlossaryEntryXRef::List m_seeAlso;
+};
+
+inline QDataStream &operator<<( QDataStream &stream, const GlossaryEntry &e )
+{
+ return stream << e.term() << e.definition() << e.seeAlso();
+}
+
+inline QDataStream &operator>>( QDataStream &stream, GlossaryEntry &e )
+{
+ return stream >> e.m_term >> e.m_definition >> e.m_seeAlso;
+}
+
+class Glossary : public KListView
+{
+ Q_OBJECT
+ public:
+ Glossary( QWidget *parent );
+ virtual ~Glossary();
+
+ const GlossaryEntry &entry( const QString &id ) const;
+
+ static QString entryToHtml( const GlossaryEntry &entry );
+
+ virtual void show();
+
+ public slots:
+ void slotSelectGlossEntry( const QString &id );
+
+ signals:
+ void entrySelected( const GlossaryEntry &entry );
+
+ private slots:
+ void meinprocExited( KProcess *meinproc );
+ void treeItemSelected( QListViewItem *item );
+
+ private:
+ enum CacheStatus { NeedRebuild, CacheOk };
+
+ CacheStatus cacheStatus() const;
+ int glossaryCTime() const;
+ void rebuildGlossaryCache();
+ void buildGlossaryTree();
+ QDomElement childElement( const QDomElement &e, const QString &name );
+
+ KConfig *m_config;
+ QListViewItem *m_byTopicItem;
+ QListViewItem *m_alphabItem;
+ QString m_sourceFile;
+ QString m_cacheFile;
+ CacheStatus m_status;
+ QDict<GlossaryEntry> m_glossEntries;
+ QDict<EntryItem> m_idDict;
+ bool m_initialized;
+};
+
+}
+
+#endif // KHC_GLOSSARY_H
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/glossary.html.in b/khelpcenter/glossary.html.in
new file mode 100644
index 00000000..343d844c
--- /dev/null
+++ b/khelpcenter/glossary.html.in
@@ -0,0 +1,95 @@
+<HTML>
+
+<HEAD>
+ <title>%1: %1</title> <!-- KDE Glossary: <Term> -->
+ <link rel="stylesheet" href="file:%1" type="text/css" /> <!-- konq.css -->
+</HEAD>
+
+<BODY BGCOLOR=#3679AD LEFTMARGIN=0 TOPMARGIN=5>
+<div style="position:absolute; left: 0px; top: 5px; right: 0px; bottom: 500px;">
+<TABLE BORDER=0 WIDTH=100% CELLPADDING=0 CELLSPACING=0 CELLPADDING=0>
+ <COLGROUP>
+ <COL WIDTH=156>
+ <COL WIDTH=20>
+ <COL WIDTH=282>
+ <COL WIDTH=*>
+ </COLGROUP>
+ <TR HEIGHT=24>
+ <TD BGCOLOR=#505050 ALIGN=RIGHT><IMG WIDTH=70 HEIGHT=22 SRC="file:%1"></TD> <!-- pointers.png -->
+ <TD BGCOLOR=#505050 COLSPAN=3></TD>
+ </TR>
+ <TR>
+ <TD WIDTH=176 COLSPAN=2 ROWSPAN=2> &nbsp;</TD>
+ <TD BGCOLOR=#DDDDDD><IMG WIDTH=282 HEIGHT=77 SRC="file:%1"></TD> <!-- khelpcenter.png -->
+ <TD BGCOLOR=#DDDDDD BACKGROUND="file:%1">&nbsp;</TD> <!-- lines.png -->
+ </TR>
+
+ <TR>
+
+ <TD COLSPAN=2 BGCOLOR=#505050 ALIGN=LEFT HEIGHT=22>
+
+<TABLE BORDER=0 CELLPADDING=0 CELLSPACING=0 CELLPADDING=0>
+ <TR>
+ <TD HEIGHT=20 class="menu">&nbsp;</TD>
+ </TR>
+</TABLE>
+ </TD>
+ </TR>
+
+ <TR>
+ <TD COLSPAN=2 WIDTH=176></TD>
+ <TD COLSPAN=2 class="shadow1" HEIGHT=9 COLSPAN=4></TD>
+ </TR>
+ <TR>
+ <TD COLSPAN=2 WIDTH=176></TD>
+ <TD COLSPAN=2 HEIGHT=46 COLSPAN=4></TD>
+ </TR>
+</TABLE>
+
+<!-- end of header -->
+
+
+<TABLE WIDTH=100% BORDER=0 CELLPADDING=0 CELLSPACING=0 CELLPADDING=0>
+<TR>
+ <TD WIDTH=114></TD>
+ <TD class="trans" BGCOLOR=#D0DFEC>
+
+ <TABLE WIDTH= 100% BORDER=0 CELLPADDING=0 CELLSPACING=0 CELLPADDING=0>
+ <TR>
+ <TD HEIGHT=20 WIDTH=20>&nbsp;</TD>
+ <TD>&nbsp;</TD>
+ </TR>
+ <TR>
+ <TD WIDTH=20>&nbsp;</TD>
+ <TD VALIGN=TOP><H2>%1</H2>%1<P>%1</TD>
+ <TD WIDTH=20>&nbsp;</TD>
+ </TR>
+ <TR>
+ <TD HEIGHT=20 WIDTH=20>&nbsp;</TD>
+ <TD>&nbsp;</TD>
+ </TR>
+
+</TABLE>
+
+ </TD>
+ <TD WIDTH=20>&nbsp;</TD>
+ </TR>
+ <TR>
+ <TD HEIGHT=44 COLSPAN=3>&nbsp;</TD>
+ </TR>
+</TR>
+</TABLE>
+<TABLE WIDTH=100% BORDER=0 CELLSPACING=0 CELLPADDING=0>
+<TR>
+<TD class="end" WIDTH=*>&nbsp;</TD>
+<TD WIDTH=204><A HREF="http://www.kde.org"> <IMG WIDTH=204 BORDER=0
+HEIGHT=57
+SRC="file:%1"></A></TD>
+</TR>
+<TR>
+ <TD HEIGHT=50 COLSPAN=2>&nbsp;</TD>
+</TR>
+</TABLE>
+</div>
+</BODY>
+</HTML>
diff --git a/khelpcenter/glossary.xslt b/khelpcenter/glossary.xslt
new file mode 100644
index 00000000..4be123a8
--- /dev/null
+++ b/khelpcenter/glossary.xslt
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="1.0">
+
+<xsl:template match="glossary">
+<glossary>
+ <xsl:apply-templates select="glossdiv"/>
+</glossary>
+</xsl:template>
+
+<xsl:template match="glossdiv">
+<section>
+ <xsl:attribute name="title"><xsl:value-of select="title"/></xsl:attribute>
+ <xsl:apply-templates select="glossentry"/>
+</section>
+</xsl:template>
+
+<xsl:template match="glossentry">
+<entry>
+ <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
+ <term><xsl:value-of select="glossterm"/></term>
+ <definition><xsl:value-of select="glossdef/*[not(name()='glossseealso')]"/></definition>
+ <references><xsl:apply-templates select="glossdef/glossseealso"/></references>
+</entry>
+</xsl:template>
+
+<xsl:template match="glossseealso">
+<reference>
+ <xsl:attribute name="term"><xsl:value-of select="."/></xsl:attribute>
+ <xsl:attribute name="id"><xsl:value-of select="@otherterm"/></xsl:attribute>
+</reference>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/khelpcenter/history.cpp b/khelpcenter/history.cpp
new file mode 100644
index 00000000..9162d764
--- /dev/null
+++ b/khelpcenter/history.cpp
@@ -0,0 +1,351 @@
+/*
+ * This file is part of the KDE Help Center
+ *
+ * Copyright (C) 2002 Frerich Raabe <raabe@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "history.h"
+#include "view.h"
+
+#include <kaction.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kmainwindow.h>
+#include <kpopupmenu.h>
+#include <kstdguiitem.h>
+#include <kstringhandler.h>
+
+
+
+using namespace KHC;
+
+History *History::m_instance = 0;
+
+History &History::self()
+{
+ if ( !m_instance )
+ m_instance = new History;
+ return *m_instance;
+}
+
+History::History() : QObject(),
+ m_goBuffer( 0 )
+{
+ m_entries.setAutoDelete( true );
+}
+
+History::~History()
+{
+}
+
+void History::setupActions( KActionCollection *coll )
+{
+ QPair<KGuiItem, KGuiItem> backForward = KStdGuiItem::backAndForward();
+
+ m_backAction = new KToolBarPopupAction( backForward.first, ALT+Key_Left,
+ this, SLOT( back() ), coll, "back" );
+ connect( m_backAction->popupMenu(), SIGNAL( activated( int ) ),
+ SLOT( backActivated( int ) ) );
+ connect( m_backAction->popupMenu(), SIGNAL( aboutToShow() ),
+ SLOT( fillBackMenu() ) );
+ m_backAction->setEnabled( false );
+
+ m_forwardAction = new KToolBarPopupAction( backForward.second, ALT+Key_Right,
+ this, SLOT( forward() ), coll,
+ "forward" );
+ connect( m_forwardAction->popupMenu(), SIGNAL( activated( int ) ),
+ SLOT( forwardActivated( int ) ) );
+ connect( m_forwardAction->popupMenu(), SIGNAL( aboutToShow() ),
+ SLOT( fillForwardMenu() ) );
+ m_forwardAction->setEnabled( false );
+}
+
+void History::installMenuBarHook( KMainWindow *mainWindow )
+{
+ QPopupMenu *goMenu = dynamic_cast<QPopupMenu *>(
+ mainWindow->guiFactory()->container( "go_web", mainWindow ) );
+ if ( goMenu ) {
+ connect( goMenu, SIGNAL( aboutToShow() ), SLOT( fillGoMenu() ) );
+ connect( goMenu, SIGNAL( activated( int ) ),
+ SLOT( goMenuActivated( int ) ) );
+ m_goMenuIndex = goMenu->count();
+ }
+}
+
+void History::createEntry()
+{
+ kdDebug() << "History::createEntry()" << endl;
+
+ // First, remove any forward history
+ Entry * current = m_entries.current();
+ if (current)
+ {
+ m_entries.at( m_entries.count() - 1 ); // go to last one
+ for ( ; m_entries.current() != current ; )
+ {
+ if ( !m_entries.removeLast() ) { // and remove from the end (faster and easier)
+ Q_ASSERT(0);
+ return;
+ }
+ else
+ m_entries.at( m_entries.count() - 1 );
+ }
+ // Now current is the current again.
+
+ // If current entry is empty reuse it.
+ if ( !current->view ) return;
+ }
+
+ // Append a new entry
+ m_entries.append( new Entry ); // made current
+ Q_ASSERT( m_entries.at() == (int) m_entries.count() - 1 );
+}
+
+void History::updateCurrentEntry( View *view )
+{
+ if ( m_entries.isEmpty() )
+ return;
+
+ KURL url = view->url();
+
+ Entry *current = m_entries.current();
+
+ QDataStream stream( current->buffer, IO_WriteOnly );
+ view->browserExtension()->saveState( stream );
+
+ current->view = view;
+
+ if ( url.isEmpty() ) {
+ kdDebug() << "History::updateCurrentEntry(): internal url" << endl;
+ url = view->internalUrl();
+ }
+
+ kdDebug() << "History::updateCurrentEntry(): " << view->title()
+ << " (URL: " << url.url() << ")" << endl;
+
+ current->url = url;
+ current->title = view->title();
+
+ current->search = view->state() == View::Search;
+}
+
+void History::updateActions()
+{
+ m_backAction->setEnabled( canGoBack() );
+ m_forwardAction->setEnabled( canGoForward() );
+}
+
+void History::back()
+{
+ kdDebug( 1400 ) << "History::back()" << endl;
+ goHistoryActivated( -1 );
+}
+
+void History::backActivated( int id )
+{
+ kdDebug( 1400 ) << "History::backActivated(): id = " << id << endl;
+ goHistoryActivated( -( m_backAction->popupMenu()->indexOf( id ) + 1 ) );
+}
+
+void History::forward()
+{
+ kdDebug( 1400 ) << "History::forward()" << endl;
+ goHistoryActivated( 1 );
+}
+
+void History::forwardActivated( int id )
+{
+ kdDebug( 1400 ) << "History::forwardActivated(): id = " << id << endl;
+ goHistoryActivated( m_forwardAction->popupMenu()->indexOf( id ) + 1 );
+}
+
+void History::goHistoryActivated( int steps )
+{
+ kdDebug( 1400 ) << "History::goHistoryActivated(): m_goBuffer = " << m_goBuffer << endl;
+ if ( m_goBuffer )
+ return;
+ m_goBuffer = steps;
+ QTimer::singleShot( 0, this, SLOT( goHistoryDelayed() ) );
+}
+
+void History::goHistoryDelayed()
+{
+ kdDebug( 1400 ) << "History::goHistoryDelayed(): m_goBuffer = " << m_goBuffer << endl;
+ if ( !m_goBuffer )
+ return;
+ int steps = m_goBuffer;
+ m_goBuffer = 0;
+ goHistory( steps );
+}
+
+void History::goHistory( int steps )
+{
+ kdDebug() << "History::goHistory(): " << steps << endl;
+
+ // If current entry is empty remove it.
+ Entry *current = m_entries.current();
+ if ( current && !current->view ) m_entries.remove();
+
+ int newPos = m_entries.at() + steps;
+
+ current = m_entries.at( newPos );
+ if ( !current ) {
+ kdError() << "No History entry at position " << newPos << endl;
+ return;
+ }
+
+ if ( !current->view ) {
+ kdWarning() << "Empty history entry." << endl;
+ return;
+ }
+
+ if ( current->search ) {
+ kdDebug() << "History::goHistory(): search" << endl;
+ current->view->lastSearch();
+ return;
+ }
+
+ if ( current->url.protocol() == "khelpcenter" ) {
+ kdDebug() << "History::goHistory(): internal" << endl;
+ emit goInternalUrl( current->url );
+ return;
+ }
+
+ kdDebug() << "History::goHistory(): restore state" << endl;
+
+ emit goUrl( current->url );
+
+ Entry h( *current );
+ h.buffer.detach();
+
+ QDataStream stream( h.buffer, IO_ReadOnly );
+
+ h.view->closeURL();
+ updateCurrentEntry( h.view );
+ h.view->browserExtension()->restoreState( stream );
+
+ updateActions();
+}
+
+void History::fillBackMenu()
+{
+ QPopupMenu *menu = m_backAction->popupMenu();
+ menu->clear();
+ fillHistoryPopup( menu, true, false, false );
+}
+
+void History::fillForwardMenu()
+{
+ QPopupMenu *menu = m_forwardAction->popupMenu();
+ menu->clear();
+ fillHistoryPopup( menu, false, true, false );
+}
+
+void History::fillGoMenu()
+{
+ KMainWindow *mainWindow = static_cast<KMainWindow *>( kapp->mainWidget() );
+ QPopupMenu *goMenu = dynamic_cast<QPopupMenu *>( mainWindow->guiFactory()->container( QString::fromLatin1( "go" ), mainWindow ) );
+ if ( !goMenu || m_goMenuIndex == -1 )
+ return;
+
+ for ( int i = goMenu->count() - 1 ; i >= m_goMenuIndex; i-- )
+ goMenu->removeItemAt( i );
+
+ // TODO perhaps smarter algorithm (rename existing items, create new ones only if not enough) ?
+
+ // Ok, we want to show 10 items in all, among which the current url...
+
+ if ( m_entries.count() <= 9 )
+ {
+ // First case: limited history in both directions -> show it all
+ m_goMenuHistoryStartPos = m_entries.count() - 1; // Start right from the end
+ } else
+ // Second case: big history, in one or both directions
+ {
+ // Assume both directions first (in this case we place the current URL in the middle)
+ m_goMenuHistoryStartPos = m_entries.at() + 4;
+
+ // Forward not big enough ?
+ if ( m_entries.at() > (int)m_entries.count() - 4 )
+ m_goMenuHistoryStartPos = m_entries.count() - 1;
+ }
+ Q_ASSERT( m_goMenuHistoryStartPos >= 0 && (uint)m_goMenuHistoryStartPos < m_entries.count() );
+ m_goMenuHistoryCurrentPos = m_entries.at(); // for slotActivated
+ fillHistoryPopup( goMenu, false, false, true, m_goMenuHistoryStartPos );
+}
+
+void History::goMenuActivated( int id )
+{
+ KMainWindow *mainWindow = static_cast<KMainWindow *>( kapp->mainWidget() );
+ QPopupMenu *goMenu = dynamic_cast<QPopupMenu *>( mainWindow->guiFactory()->container( QString::fromLatin1( "go" ), mainWindow ) );
+ if ( !goMenu )
+ return;
+
+ // 1 for first item in the list, etc.
+ int index = goMenu->indexOf(id) - m_goMenuIndex + 1;
+ if ( index > 0 )
+ {
+ kdDebug(1400) << "Item clicked has index " << index << endl;
+ // -1 for one step back, 0 for don't move, +1 for one step forward, etc.
+ int steps = ( m_goMenuHistoryStartPos+1 ) - index - m_goMenuHistoryCurrentPos; // make a drawing to understand this :-)
+ kdDebug(1400) << "Emit activated with steps = " << steps << endl;
+ goHistory( steps );
+ }
+}
+
+void History::fillHistoryPopup( QPopupMenu *popup, bool onlyBack, bool onlyForward, bool checkCurrentItem, uint startPos )
+{
+ Q_ASSERT ( popup ); // kill me if this 0... :/
+
+ Entry * current = m_entries.current();
+ QPtrListIterator<Entry> it( m_entries );
+ if (onlyBack || onlyForward)
+ {
+ it += m_entries.at(); // Jump to current item
+ if ( !onlyForward ) --it; else ++it; // And move off it
+ } else if ( startPos )
+ it += startPos; // Jump to specified start pos
+
+ uint i = 0;
+ while ( it.current() )
+ {
+ QString text = it.current()->title;
+ text = KStringHandler::csqueeze(text, 50); //CT: squeeze
+ text.replace( "&", "&&" );
+ if ( checkCurrentItem && it.current() == current )
+ {
+ int id = popup->insertItem( text ); // no pixmap if checked
+ popup->setItemChecked( id, true );
+ } else
+ popup->insertItem( text );
+ if ( ++i > 10 )
+ break;
+ if ( !onlyForward ) --it; else ++it;
+ }
+}
+
+bool History::canGoBack() const
+{
+ return m_entries.at() > 0;
+}
+
+bool History::canGoForward() const
+{
+ return m_entries.at() != static_cast<int>( m_entries.count() ) - 1;
+}
+
+#include "history.moc"
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/history.h b/khelpcenter/history.h
new file mode 100644
index 00000000..2198016b
--- /dev/null
+++ b/khelpcenter/history.h
@@ -0,0 +1,107 @@
+/*
+ * This file is part of the KDE Help Center
+ *
+ * Copyright (C) 2002 Frerich Raabe <raabe@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef HISTORY_H
+#define HISTORY_H
+
+#include <kurl.h>
+
+#include <qobject.h>
+#include <qptrlist.h>
+
+class KActionCollection;
+class KMainWindow;
+class KToolBarPopupAction;
+class QPopupMenu;
+
+namespace KHC {
+
+class View;
+
+class History : public QObject
+{
+ Q_OBJECT
+ public:
+ friend class foo; // to make gcc shut up
+ struct Entry
+ {
+ Entry() : view( 0 ), search( false ) {}
+
+ View *view;
+ KURL url;
+ QString title;
+ QByteArray buffer;
+ bool search;
+ };
+
+ static History &self();
+
+ void setupActions( KActionCollection *coll );
+ void updateActions();
+
+ void installMenuBarHook( KMainWindow *mainWindow );
+
+ void createEntry();
+ void updateCurrentEntry( KHC::View *view );
+
+ signals:
+ void goInternalUrl( const KURL & );
+ void goUrl( const KURL & );
+
+ private slots:
+ void backActivated( int id );
+ void fillBackMenu();
+ void forwardActivated( int id );
+ void fillForwardMenu();
+ void goMenuActivated( int id );
+ void fillGoMenu();
+ void back();
+ void forward();
+ void goHistoryActivated( int steps );
+ void goHistory( int steps );
+ void goHistoryDelayed();
+
+ private:
+ History();
+ History( const History &rhs );
+ History &operator=( const History &rhs );
+ ~History();
+
+ bool canGoBack() const;
+ bool canGoForward() const;
+ void fillHistoryPopup( QPopupMenu *, bool, bool, bool, uint = 0 );
+
+ static History *m_instance;
+
+ QPtrList<Entry> m_entries;
+
+
+ int m_goBuffer;
+ int m_goMenuIndex;
+ int m_goMenuHistoryStartPos;
+ int m_goMenuHistoryCurrentPos;
+ public:
+ KToolBarPopupAction *m_backAction;
+ KToolBarPopupAction *m_forwardAction;
+};
+
+}
+
+#endif // HISTORY_H
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/htmlsearch.cpp b/khelpcenter/htmlsearch.cpp
new file mode 100644
index 00000000..9c469ae8
--- /dev/null
+++ b/khelpcenter/htmlsearch.cpp
@@ -0,0 +1,61 @@
+#include <kdebug.h>
+#include <kconfig.h>
+
+#include "docentry.h"
+
+#include "htmlsearch.h"
+#include "htmlsearch.moc"
+
+using namespace KHC;
+
+HTMLSearch::HTMLSearch()
+{
+ mConfig = new KConfig("khelpcenterrc", true);
+ mConfig->setGroup( "htdig" );
+}
+
+HTMLSearch::~HTMLSearch()
+{
+ delete mConfig;
+}
+
+void HTMLSearch::setupDocEntry( KHC::DocEntry *entry )
+{
+// kdDebug() << "HTMLSearch::setupDocEntry(): " << entry->name() << endl;
+
+ if ( entry->searchMethod().lower() != "htdig" ) return;
+
+ if ( entry->search().isEmpty() )
+ entry->setSearch( defaultSearch( entry ) );
+ if ( entry->indexer().isEmpty() )
+ entry->setIndexer( defaultIndexer( entry ) );
+ if ( entry->indexTestFile().isEmpty() )
+ entry->setIndexTestFile( defaultIndexTestFile( entry ) );
+
+// entry->dump();
+}
+
+QString HTMLSearch::defaultSearch( KHC::DocEntry *entry )
+{
+ QString htsearch = "cgi:";
+ htsearch += mConfig->readPathEntry( "htsearch" );
+ htsearch += "?words=%k&method=and&format=-desc&config=";
+ htsearch += entry->identifier();
+
+ return htsearch;
+}
+
+QString HTMLSearch::defaultIndexer( KHC::DocEntry * )
+{
+ QString indexer = mConfig->readPathEntry( "indexer" );
+ indexer += " --indexdir=%i %f";
+
+ return indexer;
+}
+
+QString HTMLSearch::defaultIndexTestFile( KHC::DocEntry *entry )
+{
+ return entry->identifier() + ".exists";
+}
+
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/htmlsearch.h b/khelpcenter/htmlsearch.h
new file mode 100644
index 00000000..84fb9181
--- /dev/null
+++ b/khelpcenter/htmlsearch.h
@@ -0,0 +1,33 @@
+#ifndef KHC_HTMLSEARCH_H
+#define KHC_HTMLSEARCH_H
+
+#include <qobject.h>
+#include <qstring.h>
+
+class KConfig;
+
+namespace KHC {
+
+class DocEntry;
+
+class HTMLSearch : public QObject
+{
+ Q_OBJECT
+ public:
+ HTMLSearch();
+ ~HTMLSearch();
+
+ void setupDocEntry( KHC::DocEntry * );
+
+ QString defaultSearch( KHC::DocEntry * );
+ QString defaultIndexer( KHC::DocEntry * );
+ QString defaultIndexTestFile( KHC::DocEntry * );
+
+ private:
+ KConfig *mConfig;
+};
+
+}
+
+#endif
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/htmlsearch/Makefile.am b/khelpcenter/htmlsearch/Makefile.am
new file mode 100644
index 00000000..f287fa11
--- /dev/null
+++ b/khelpcenter/htmlsearch/Makefile.am
@@ -0,0 +1,39 @@
+khelpcenter_en_data_DATA = long.html short.html wrapper.html nomatch.html syntax.html
+khelpcenter_en_datadir = $(kde_datadir)/khelpcenter/en
+
+star_DATA = star.png star_blank.png
+stardir = $(kde_datadir)/khelpcenter/pics
+
+INCLUDES = $(all_includes)
+METASOURCES = AUTO
+
+lib_LTLIBRARIES = libhtmlsearch.la libkcm_htmlsearch.la
+
+libhtmlsearch_la_SOURCES = htmlsearch.cpp progressdialog.cpp
+libhtmlsearch_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+libhtmlsearch_la_LIBADD = $(LIB_KIO)
+
+libkcm_htmlsearch_la_SOURCES = kcmhtmlsearch.cpp klangcombo.cpp ktagcombobox.cpp
+libkcm_htmlsearch_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+libkcm_htmlsearch_la_LIBADD = $(LIB_KIO)
+
+noinst_HEADERS = kcmhtmlsearch.h htmlsearch.h
+
+xdg_apps_DATA = htmlsearch.desktop
+
+bin_PROGRAMS = khtmlindex
+
+wrapperdir = $(kde_datadir)/khelpcenter/
+wrapper_SCRIPTS = meinproc_wrapper
+
+khtmlindex_SOURCES = index.cpp
+khtmlindex_LDFLAGS = $(KDE_RPATH) $(all_libraries)
+khtmlindex_LDADD = libhtmlsearch.la $(LIB_KDEUI)
+
+xpm_DATA = unchecked.xpm checked.xpm
+xpmdir = $(kde_datadir)/khelpcenter/pics
+
+messages:
+ $(XGETTEXT) index.cpp $(libhtmlsearch_la_SOURCES) -o $(podir)/htmlsearch.pot
+ $(XGETTEXT) $(libkcm_htmlsearch_la_SOURCES) -o $(podir)/kcmhtmlsearch.pot
+
diff --git a/khelpcenter/htmlsearch/checked.xpm b/khelpcenter/htmlsearch/checked.xpm
new file mode 100644
index 00000000..1ed19024
--- /dev/null
+++ b/khelpcenter/htmlsearch/checked.xpm
@@ -0,0 +1,23 @@
+/* XPM */
+static char*unchecked[]={
+"16 16 4 1",
+"# c #000000",
+"+ c #ffffff",
+"D c #000000",
+". c None",
+"................",
+"............++++",
+"..++++++++++DDD+",
+"..+########DDD+.",
+"..+#++++++DDD+..",
+"+DDD+...+DDD#+..",
+"++DDD+++DDD+#+..",
+"..+DDDDDDD++#+..",
+"..+#DDDDD+.+#+..",
+"..+#++DD+..+#+..",
+"..+#+++++..+#+..",
+"..+#++++++++#+..",
+"..+##########+..",
+"..++++++++++++..",
+"................",
+"................"};
diff --git a/khelpcenter/htmlsearch/htmlsearch.cpp b/khelpcenter/htmlsearch/htmlsearch.cpp
new file mode 100644
index 00000000..02d09d14
--- /dev/null
+++ b/khelpcenter/htmlsearch/htmlsearch.cpp
@@ -0,0 +1,487 @@
+#include <qregexp.h>
+#include <qdir.h>
+#include <assert.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kstandarddirs.h>
+#include <kprocess.h>
+#include <klocale.h>
+#include <kconfig.h>
+
+
+#include "progressdialog.h"
+#include "htmlsearch.moc"
+
+
+HTMLSearch::HTMLSearch()
+ : QObject(), _proc(0)
+{
+}
+
+
+QString HTMLSearch::dataPath(const QString& _lang)
+{
+ return kapp->dirs()->saveLocation("data", QString("khelpcenter/%1").arg(_lang));
+}
+
+
+void HTMLSearch::scanDir(const QString& dir)
+{
+ assert( dir.at( dir.length() - 1 ) == '/' );
+
+ QStringList::ConstIterator it;
+
+ if ( KStandardDirs::exists( dir + "index.docbook" ) ) {
+ _files.append(dir + "index.docbook");
+ progress->setFilesScanned(++_filesScanned);
+ } else {
+ QDir d(dir, "*.html", QDir::Name|QDir::IgnoreCase, QDir::Files | QDir::Readable);
+ QStringList const &list = d.entryList();
+ QString adir = d.canonicalPath () + "/";
+ QString file;
+ for (it=list.begin(); it != list.end(); ++it)
+ {
+ file = adir + *it;
+ if ( !_files.contains( file ) ) {
+ _files.append(file);
+ progress->setFilesScanned(++_filesScanned);
+ }
+ }
+ }
+
+ QDir d2(dir, QString::null, QDir::Name|QDir::IgnoreCase, QDir::Dirs);
+ QStringList const &dlist = d2.entryList();
+ for (it=dlist.begin(); it != dlist.end(); ++it)
+ if (*it != "." && *it != "..")
+ {
+ scanDir(dir + *it + "/");
+ kapp->processEvents();
+ }
+}
+
+
+bool HTMLSearch::saveFilesList(const QString& _lang)
+{
+ QStringList dirs;
+
+ // throw away old files list
+ _files.clear();
+
+ // open config file
+ KConfig *config = new KConfig("khelpcenterrc");
+ config->setGroup("Scope");
+
+ // add KDE help dirs
+ if (config->readBoolEntry("KDE", true))
+ dirs = kapp->dirs()->findDirs("html", _lang + "/");
+ kdDebug() << "got " << dirs.count() << " dirs\n";
+
+ // TODO: Man and Info!!
+
+ // add local urls
+ QStringList add = config->readListEntry("Paths");
+ QStringList::Iterator it;
+ for (it = add.begin(); it != add.end(); ++it) {
+ if ( ( *it ).at( ( *it ).length() - 1 ) != '/' )
+ ( *it ) += '/';
+ dirs.append(*it);
+ }
+
+ _filesScanned = 0;
+
+ for (it = dirs.begin(); it != dirs.end(); ++it)
+ scanDir(*it);
+
+ delete config;
+
+ return true;
+}
+
+
+bool HTMLSearch::createConfig(const QString& _lang)
+{
+ QString fname = dataPath(_lang) + "/htdig.conf";
+
+ // locate the common dir
+ QString wrapper = locate("data", QString("khelpcenter/%1/wrapper.html").arg(_lang));
+ if (wrapper.isEmpty())
+ wrapper = locate("data", QString("khelpcenter/en/wrapper.html"));
+ if (wrapper.isEmpty())
+ return false;
+ wrapper = wrapper.left(wrapper.length() - 12);
+
+ // locate the image dir
+ QString images = locate("data", "khelpcenter/pics/star.png");
+ if (images.isEmpty())
+ return false;
+ images = images.left(images.length() - 8);
+
+ // This is an example replacement for the default bad_words file
+ // distributed with ht://Dig. It was compiled by Marjolein Katsma
+ // <HSH@taxon.demon.nl>.
+ QString bad_words = i18n( "List of words to exclude from index",
+ "above:about:according:across:actually:\n"
+ "adj:after:afterwards:again:against:all:\n"
+ "almost:alone:along:already:also:although:\n"
+ "always:among:amongst:and:another:any:\n"
+ "anyhow:anyone:anything:anywhere:are:aren:\n"
+ "arent:around:became:because:become:\n"
+ "becomes:becoming:been:before:beforehand:\n"
+ "begin:beginning:behind:being:below:beside:\n"
+ "besides:between:beyond:billion:both:but:\n"
+ "can:cant:cannot:caption:could:couldnt:\n"
+ "did:didnt:does:doesnt:dont:down:during:\n"
+ "each:eight:eighty:either:else:elsewhere:\n"
+ "end:ending:enough:etc:even:ever:every:\n"
+ "everyone:everything:everywhere:except:few:\n"
+ "fifty:first:five:for:former:formerly:forty:\n"
+ "found:four:from:further:had:has:hasnt:have:\n"
+ "havent:hence:her:here:hereafter:hereby:\n"
+ "herein:heres:hereupon:hers:herself:hes:him:\n"
+ "himself:his:how:however:hundred:\n"
+ "inc:indeed:instead:into:isnt:its:\n"
+ "itself:last:later:latter:latterly:least:\n"
+ "less:let:like:likely:ltd:made:make:makes:\n"
+ "many:may:maybe:meantime:meanwhile:might:\n"
+ "million:miss:more:moreover:most:mostly:\n"
+ "mrs:much:must:myself:namely:neither:\n"
+ "never:nevertheless:next:nine:ninety:\n"
+ "nobody:none:nonetheless:noone:nor:not:\n"
+ "nothing:now:nowhere:off:often:once:\n"
+ "one:only:onto:others:otherwise:our:ours:\n"
+ "ourselves:out:over:overall:own:page:per:\n"
+ "perhaps:rather:recent:recently:same:\n"
+ "seem:seemed:seeming:seems:seven:seventy:\n"
+ "several:she:shes:should:shouldnt:since:six:\n"
+ "sixty:some:somehow:someone:something:\n"
+ "sometime:sometimes:somewhere:still:stop:\n"
+ "such:taking:ten:than:that:the:their:them:\n"
+ "themselves:then:thence:there:thereafter:\n"
+ "thereby:therefore:therein:thereupon:these:\n"
+ "they:thirty:this:those:though:thousand:\n"
+ "three:through:throughout:thru:thus:tips:\n"
+ "together:too:toward:towards:trillion:\n"
+ "twenty:two:under:unless:unlike:unlikely:\n"
+ "until:update:updated:updates:upon:\n"
+ "used:using:very:via:want:wanted:wants:\n"
+ "was:wasnt:way:ways:wed:well:were:\n"
+ "werent:what:whats:whatever:when:whence:\n"
+ "whenever:where:whereafter:whereas:whereby:\n"
+ "wherein:whereupon:wherever:wheres:whether:\n"
+ "which:while:whither:who:whoever:whole:\n"
+ "whom:whomever:whose:why:will:with:within:\n"
+ "without:wont:work:worked:works:working:\n"
+ "would:wouldnt:yes:yet:you:youd:youll:your:\n"
+ "youre:yours:yourself:yourselves:youve" );
+
+ QFile f;
+ f.setName( dataPath(_lang) + "/bad_words" );
+ if (f.open(IO_WriteOnly))
+ {
+ QTextStream ts( &f );
+ QStringList words = QStringList::split ( QRegExp ( "[\n:]" ),
+ bad_words, false);
+ for ( QStringList::ConstIterator it = words.begin();
+ it != words.end(); ++it )
+ ts << *it << endl;
+ f.close();
+ }
+
+ f.setName(fname);
+ if (f.open(IO_WriteOnly))
+ {
+ kdDebug() << "Writing config for " << _lang << " to " << fname << endl;
+
+ QTextStream ts(&f);
+
+ ts << "database_dir:\t\t" << dataPath(_lang) << endl;
+ ts << "start_url:\t\t`" << dataPath(_lang) << "/files`" << endl;
+ ts << "local_urls:\t\tfile:/=/" << endl;
+ ts << "local_urls_only:\ttrue" << endl;
+ ts << "maximum_pages:\t\t1" << endl;
+ ts << "image_url_prefix:\t" << images << endl;
+ ts << "star_image:\t\t" << images << "star.png" << endl;
+ ts << "star_blank:\t\t" << images << "star_blank.png" << endl;
+ ts << "compression_level:\t6" << endl;
+ ts << "max_hop_count:\t\t0" << endl;
+
+ ts << "search_results_wrapper:\t" << wrapper << "wrapper.html" << endl;
+ ts << "nothing_found_file:\t" << wrapper << "nomatch.html" << endl;
+ ts << "syntax_error_file:\t" << wrapper << "syntax.html" << endl;
+ ts << "bad_word_list:\t\t" << dataPath(_lang) << "/bad_words" << endl;
+ ts << "external_parsers:\t" << "text/xml\t" << locate( "data", "khelpcenter/meinproc_wrapper" ) << endl;
+ f.close();
+ return true;
+ }
+
+ return false;
+}
+
+
+#define CHUNK_SIZE 15
+
+bool HTMLSearch::generateIndex(QString _lang, QWidget *parent)
+{
+ if (_lang == "C")
+ _lang = "en";
+
+ if (!createConfig(_lang))
+ return false;
+
+ // create progress dialog
+ progress = new ProgressDialog(parent);
+ progress->show();
+ kapp->processEvents();
+
+ // create files list ----------------------------------------------
+ if (!saveFilesList(_lang))
+ return false;
+
+ progress->setState(1);
+
+ // run htdig ------------------------------------------------------
+ KConfig *config = new KConfig("khelpcenterrc", true);
+ KConfigGroupSaver saver(config, "htdig");
+ QString exe = config->readPathEntry("htdig", kapp->dirs()->findExe("htdig"));
+
+ if (exe.isEmpty())
+ {
+ delete config;
+ return false;
+ }
+ bool initial = true;
+ bool done = false;
+ int count = 0;
+
+ _filesToDig = _files.count();
+ progress->setFilesToDig(_filesToDig);
+ _filesDigged = 0;
+
+ QDir d; d.mkdir(dataPath(_lang));
+
+ while (!done)
+ {
+ // kill old process
+ delete _proc;
+
+ // prepare new process
+ _proc = new KProcess();
+ *_proc << exe << "-v" << "-c" << dataPath(_lang)+"/htdig.conf";
+ if (initial)
+ {
+ *_proc << "-i";
+ initial = false;
+ }
+
+ kdDebug() << "Running htdig" << endl;
+
+ connect(_proc, SIGNAL(receivedStdout(KProcess *,char*,int)),
+ this, SLOT(htdigStdout(KProcess *,char*,int)));
+
+ connect(_proc, SIGNAL(processExited(KProcess *)),
+ this, SLOT(htdigExited(KProcess *)));
+
+ _htdigRunning = true;
+
+ // write out file
+ QFile f(dataPath(_lang)+"/files");
+ if (f.open(IO_WriteOnly))
+ {
+ QTextStream ts(&f);
+
+ for (int i=0; i<CHUNK_SIZE; ++i, ++count)
+ if (count < _filesToDig) {
+ ts << "file://" + _files[count] << endl;
+ } else {
+ done = true;
+ break;
+ }
+ f.close();
+ }
+ else
+ {
+ kdDebug() << "Could not open `files` for writing" << endl;
+ delete config;
+ return false;
+ }
+
+
+ // execute htdig
+ _proc->start(KProcess::NotifyOnExit, KProcess::Stdout );
+
+ kapp->enter_loop();
+
+ if (!_proc->normalExit() || _proc->exitStatus() != 0)
+ {
+ delete _proc;
+ delete progress;
+ delete config;
+ return false;
+ }
+
+ // _filesDigged += CHUNK_SIZE;
+ progress->setFilesDigged(_filesDigged);
+ kapp->processEvents();
+ }
+
+ progress->setState(2);
+
+ // run htmerge -----------------------------------------------------
+ exe = config->readPathEntry("htmerge", kapp->dirs()->findExe("htmerge"));
+ if (exe.isEmpty())
+ {
+ delete config;
+ return false;
+ }
+ delete _proc;
+ _proc = new KProcess();
+ *_proc << exe << "-c" << dataPath(_lang)+"/htdig.conf";
+
+ kdDebug() << "Running htmerge" << endl;
+
+ connect(_proc, SIGNAL(processExited(KProcess *)),
+ this, SLOT(htmergeExited(KProcess *)));
+
+ _htmergeRunning = true;
+
+ _proc->start(KProcess::NotifyOnExit, KProcess::Stdout);
+
+ kapp->enter_loop();
+
+ if (!_proc->normalExit() || _proc->exitStatus() != 0)
+ {
+ delete _proc;
+ delete progress;
+ delete config;
+ return false;
+ }
+
+ delete _proc;
+
+ progress->setState(3);
+ kapp->processEvents();
+
+ delete progress;
+ delete config;
+
+ return true;
+}
+
+
+
+void HTMLSearch::htdigStdout(KProcess *, char *buffer, int len)
+{
+ QString line = QString(buffer).left(len);
+
+ int cnt=0, index=-1;
+ while ( (index = line.find("file://", index+1)) > 0)
+ cnt++;
+ _filesDigged += cnt;
+
+ cnt=0;
+ index=-1;
+ while ( (index = line.find("not changed", index+1)) > 0)
+ cnt++;
+ _filesDigged -= cnt;
+
+ progress->setFilesDigged(_filesDigged);
+}
+
+
+void HTMLSearch::htdigExited(KProcess *p)
+{
+ kdDebug() << "htdig terminated " << p->exitStatus() << endl;
+ _htdigRunning = false;
+ kapp->exit_loop();
+}
+
+
+void HTMLSearch::htmergeExited(KProcess *)
+{
+ kdDebug() << "htmerge terminated" << endl;
+ _htmergeRunning = false;
+ kapp->exit_loop();
+}
+
+
+void HTMLSearch::htsearchStdout(KProcess *, char *buffer, int len)
+{
+ _searchResult += QString::fromLocal8Bit(buffer,len);
+}
+
+
+void HTMLSearch::htsearchExited(KProcess *)
+{
+ kdDebug() << "htsearch terminated" << endl;
+ _htsearchRunning = false;
+ kapp->exit_loop();
+}
+
+
+QString HTMLSearch::search(QString _lang, QString words, QString method, int matches,
+ QString format, QString sort)
+{
+ if (_lang == "C")
+ _lang = "en";
+
+ createConfig(_lang);
+
+ QString result = dataPath(_lang)+"/result.html";
+
+ // run htsearch ----------------------------------------------------
+ KConfig *config = new KConfig("khelpcenterrc", true);
+ KConfigGroupSaver saver(config, "htdig");
+ QString exe = config->readPathEntry("htsearch", kapp->dirs()->findExe("htsearch"));
+ if (exe.isEmpty())
+ {
+ delete config;
+ return QString::null;
+ }
+ _proc = new KProcess();
+ *_proc << exe << "-c" << dataPath(_lang)+"/htdig.conf" <<
+ QString("words=%1;method=%2;matchesperpage=%3;format=%4;sort=%5").arg(words).arg(method).arg(matches).arg(format).arg(sort);
+
+ kdDebug() << "Running htsearch" << endl;
+
+ connect(_proc, SIGNAL(receivedStdout(KProcess *,char*,int)),
+ this, SLOT(htsearchStdout(KProcess *,char*,int)));
+ connect(_proc, SIGNAL(processExited(KProcess *)),
+ this, SLOT(htsearchExited(KProcess *)));
+
+ _htsearchRunning = true;
+ _searchResult = "";
+
+ _proc->start(KProcess::NotifyOnExit, KProcess::Stdout);
+
+ kapp->enter_loop();
+
+ if (!_proc->normalExit() || _proc->exitStatus() != 0)
+ {
+ kdDebug() << "Error running htsearch... returning now" << endl;
+ delete _proc;
+ delete config;
+ return QString::null;
+ }
+
+ delete _proc;
+
+ // modify the search result
+ _searchResult = _searchResult.replace("http://localhost/", "file:/");
+ _searchResult = _searchResult.replace("Content-type: text/html", QString::null);
+
+ // dump the search result
+ QFile f(result);
+ if (f.open(IO_WriteOnly))
+ {
+ QTextStream ts(&f);
+
+ ts << _searchResult << endl;
+
+ f.close();
+ delete config;
+ return result;
+ }
+ delete config;
+ return QString::null;
+}
diff --git a/khelpcenter/htmlsearch/htmlsearch.desktop b/khelpcenter/htmlsearch/htmlsearch.desktop
new file mode 100644
index 00000000..1879ae74
--- /dev/null
+++ b/khelpcenter/htmlsearch/htmlsearch.desktop
@@ -0,0 +1,239 @@
+[Desktop Entry]
+Exec=kcmshell htmlsearch
+Icon=help_index
+Type=Application
+DocPath=kcontrol/help-index.html
+
+X-KDE-ModuleType=Library
+X-KDE-Library=htmlsearch
+X-KDE-FactoryName=htmlsearch
+X-KDE-ControlModuleType=User
+
+Name=Index
+Name[af]=Indeks
+Name[ar]=الفهرس
+Name[az]=İndeks
+Name[be]=Індэкс
+Name[bg]=Индекс
+Name[bn]=সূচি
+Name[br]=Meneger
+Name[bs]=Indeks
+Name[ca]=Índex
+Name[cs]=Rejstřík
+Name[csb]=Indeks
+Name[cy]=Mynegai
+Name[da]=Indeks
+Name[de]=Stichwortverzeichnis
+Name[el]=Ευρετήριο
+Name[eo]=Indekso
+Name[es]=Índice
+Name[et]=Indeks
+Name[eu]=Indizea
+Name[fa]=نمایه
+Name[fi]=Hakemisto
+Name[fy]=Yndeks
+Name[ga]=Innéacs
+Name[gl]=Índice
+Name[he]=אינדקס
+Name[hi]=सूची
+Name[hr]=Indeks
+Name[hu]=Keresési index
+Name[id]=Indeks
+Name[is]=Yfirlit
+Name[it]=Indice
+Name[ja]=インデックス
+Name[ka]=ინდექსი
+Name[kk]=Индекс
+Name[km]=លិបិក្រម
+Name[ko]=찾아보기
+Name[lo]=ດັດສະນີ
+Name[lt]=Rodyklė
+Name[lv]=Indekss
+Name[mk]=Индекс
+Name[mn]=Товчоон
+Name[ms]=Indeks
+Name[mt]=Indiċi
+Name[nb]=Indeks
+Name[ne]=अनुक्रमणिका
+Name[nn]=Indeks
+Name[nso]=Palo ya Bangwadi
+Name[pa]=ਤਤਕਰਾ
+Name[pl]=Indeks
+Name[pt]=Índice
+Name[pt_BR]=Índice
+Name[ru]=Индекс
+Name[rw]=Umubarendanga
+Name[se]=Indeaksa
+Name[sk]=Katalóg
+Name[sl]=Indeks
+Name[sr]=Индекс
+Name[sr@Latn]=Indeks
+Name[ss]=Indzikimba
+Name[ta]=பொருளடக்கம்
+Name[te]=సూచిక
+Name[tg]=Феҳрист
+Name[th]=ดัชนี
+Name[tr]=İndeks
+Name[tt]=İsemlek
+Name[uk]=Індекс
+Name[uz]=Indeks
+Name[uz@cyrillic]=Индекс
+Name[ven]=Mafhelelo a bugu
+Name[vi]=Danh mục
+Name[wa]=Indecse
+Name[xh]=Isalathiso
+Name[zh_CN]=索引
+Name[zh_TW]=索引
+Name[zu]=Uhlelo lokuqukethwe
+
+Comment=Index generation
+Comment[af]=Indeks genereering
+Comment[ar]=توليد الفهارس
+Comment[az]=İndeks yaratma
+Comment[be]=Стварэнне індэксу
+Comment[bg]=Създаване на индекс
+Comment[bn]=সূচি উত্‍পাদন
+Comment[br]=Genel ar meneger
+Comment[bs]=Pravljenje indeksa
+Comment[ca]=Generació de l'índex
+Comment[cs]=Vytvoření rejstříku
+Comment[csb]=Generowanié indeksu
+Comment[cy]=Cynhyrchu mynegai
+Comment[da]=Indeksgenerering
+Comment[de]=Erstellung des Stichwortverzeichnisses
+Comment[el]=Δημιουργία περιεχομένων
+Comment[eo]=Indekskreado
+Comment[es]=Generación del índice
+Comment[et]=Indeksi tekitamine
+Comment[eu]=Indizea sortu
+Comment[fa]=تولید نمایه
+Comment[fi]=Hakemiston luonti
+Comment[fr]=Génération d'index
+Comment[fy]=Yndeksgeneraasje
+Comment[gl]=Xeración de Índices
+Comment[he]=יצירת אינדקס
+Comment[hi]=सूची बनाएँ
+Comment[hr]=Generiranje indeksa
+Comment[hu]=Index létrehozása
+Comment[id]=Pembuatan Index
+Comment[is]=Yfirlitsgerð
+Comment[it]=Generazione dell'indice
+Comment[ja]=インデックスを生成
+Comment[ka]=ინდექსის შექმნა
+Comment[kk]=Индексті құру
+Comment[km]=ការ​បង្កើត​លិបិក្រម
+Comment[ko]=찾아보기 생성
+Comment[lo]=ສ້າງດັດສະນີ
+Comment[lt]=Rodyklės generavimas
+Comment[lv]=Indeksa ģenerēšana
+Comment[mk]=Генерирање на индекс
+Comment[mn]=Товчоон үүсгэх
+Comment[ms]=Penjanaan indeks
+Comment[mt]=Ġenerazzjoni tal-Indiċi
+Comment[nb]=Indekslaging
+Comment[nds]=Index maken
+Comment[ne]=अनुक्रमणिका उत्पादन
+Comment[nl]=Indexgeneratie
+Comment[nn]=Indekslaging
+Comment[nso]=Thlagiso ya Palo ya Bangwadi
+Comment[oc]=Generacion de l'index
+Comment[pa]=ਤਤਕਰਾ ਬਣਾਓ
+Comment[pl]=Generowanie indeksu
+Comment[pt]=Geração de índices
+Comment[pt_BR]=Geração de índice
+Comment[ro]=Generează indexul
+Comment[ru]=Создание индекса
+Comment[rw]=Irema ry'Umubarendanga
+Comment[se]=Indeaksaráhkadeapmi
+Comment[sk]=Generovanie katalógu
+Comment[sl]=Ustvarjanje indeksa
+Comment[sr]=Генерисање индекса
+Comment[sr@Latn]=Generisanje indeksa
+Comment[sv]=Indexskapare
+Comment[ta]=பொருளடக்க இயக்கம்
+Comment[te]=సూచిక ను తయారుచెయుట
+Comment[tg]=Эҷоди феҳрист
+Comment[th]=สร้างดัชนี
+Comment[tr]=İndeks oluşturma
+Comment[tt]=İsemlek ürçetü
+Comment[uk]=Утворення індексу
+Comment[uz]=Indeksni yaratish
+Comment[uz@cyrillic]=Индексни яратиш
+Comment[ven]=Murafho wa Index
+Comment[vi]=Tạo danh mục
+Comment[wa]=Ahiver l' indecse
+Comment[xh]=Ulwenziwo Lwesalathiso
+Comment[zh_CN]=索引生成
+Comment[zh_TW]=產生索引
+Comment[zu]=Ukugaywa kohlelo lokuqukethwe
+
+Keywords=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language
+Keywords[ar]=مساعدة,HTML,بحث,فهرس,htdig,htsearch,htmerge,Scope,اللغة
+Keywords[az]=Yardım,HTML,Axtar,İndeks,htdig,htmerge,Dil
+Keywords[be]=Дапамога,Даведка,Пошук,Індэкс,Мова,Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language
+Keywords[bg]=помощ, индекс, търсене, обхват, език, Help, HTML, Search, Index, htdig, htsearch, htmerge, Scope, Language
+Keywords[ca]=Ajuda,HTML,Cerca,Índex,htdig,htsearch,htmerge,Scope,Llengua
+Keywords[cs]=Nápověda,HTML,Hledat,Index,htdig,htsearch,htmerge,Rejstřík,Jazyk,Rozsah
+Keywords[csb]=pòmòc,HTML,szëkôj,szëkba,indeks,htdig,htsearch,htmerge,òbjim,jãzëk
+Keywords[cy]=Cymorth,HTML,Chwilio,Mynegai,htdig,htsearch,htmerge,Amrediad,Iaith
+Keywords[da]=Hjælp,HTML,Søg,Indeks,htdig,htsearch,htmerge,Scope,Sprog
+Keywords[de]=Hilfe,HTML,Suche,Index,Stichwortverzeichnis,htdig,Sprachen
+Keywords[el]=Βοήθεια,HTML,Αναζήτηση,Ευρετήριο,htdig,htsearch,htmerge,Scope,Γλώσσα
+Keywords[eo]=helpo,HTML,serĉo,indekso,htdig,htsearch,htmerge,areo,lingvo
+Keywords[es]=Ayuda,HTML,Búsqueda,Índice,htdig,htsearch,htmerge,Ámbito,Idioma
+Keywords[et]=abi,HTML,otsing,indeks,htdig,htsearch,htmerge,skoop,keel
+Keywords[eu]=Laguntza,HTML,Bilatu,Indizea,htdig,htsearch,htmerge,Scope,Hizkuntza
+Keywords[fa]=کمک، زنگام، جستجو، نمایه، htdig، htsearch، htmerge، دامنه، زبان
+Keywords[fi]=Ohje,HTML,Etsi,Indeksi,htdig,htsearch,htmerge,Kieli
+Keywords[fr]=aide,HTML,recherche,index,htdig,htsearch,htmerge,pays,langue
+Keywords[fy]=help,html,zoeken,sykje,yndeks,htdig,htsearch,htmerge,scope,taal
+Keywords[ga]=Cabhair,HTML,Cuardach,Innéacs,htdig,htsearch,htmerge,Scóip,Teanga
+Keywords[gl]=Axuda,HTML,Procura,Índice,htdig,htsearch,htmerge,Scope,Lingua
+Keywords[he]=עזרה,HTML,חיפוש,אינדקס,htdig,htsearch,htmerge,טווח,שפה,Help,Search,Index,htdig,htsearch,htmerge,Scope,Language
+Keywords[hi]=मदद,एचटीएमएल,खोज,तालिका,एचटीडिक,एचटीसर्च,एचटीमर्ज,स्कोप,भाषा
+Keywords[hr]=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language,Pomoć,Pretraživanje,Traži,Pretraga,Indeks,Opseg,Raspon,Jezik
+Keywords[hu]=segítség,HTML,keresés,index,htdig,htsearch,htmerge,érvényességi kör,nyelv
+Keywords[id]=Bantuan,HTML,Cari,Indeks,htdig,htsearch,htmerge,Scope,Language
+Keywords[is]=Hjálp,HTML,leit,yfirlit,htdig,svæði,tungumál
+Keywords[it]=aiuto,HTML,cerca,indice,htdig,htsearch,htmerge,scope,lingua
+Keywords[ja]=ヘルプ,HTML,検索,インデックス,htdig,htsearch,htmerge,スコープ,言語
+Keywords[km]=ជំនួយ,HTML,ស្វែងរក,លិបិក្រម,htdig,htsearch,htmerge,វិសាលភាព,ភាសា
+Keywords[lo]=ຊ່ວຍເຫລືອ,HTML,ຄົ້ນຫາດັດສະນີ,htdig,htsearch,htmerge,Scope,ພາສາ
+Keywords[lt]=Pagalba,HTML,Paieška,Sąrašas,htdig,htsearch,htmerge,Sritis,Kalba
+Keywords[lv]=Palīdzība,HTML,Meklēt,Indekss,htdig,htsearch,htmerge,Mērķis,Valoda
+Keywords[mk]=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language, Помош,Пребарувај,Индекс,Опфат,Јазик
+Keywords[mn]=Тусламж,HTML,Хайх,Товчоо,Товчоон,htdig,Хэлүүд
+Keywords[mt]=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language,Għajnuna,Fittex,Indiċi
+Keywords[nb]=Hjelp,HTML,Søk,Indeks,htdig,htsearch,htmerge,språk
+Keywords[nds]=Hülp,HTML,Söken,Index,htdig,htsearch,htmerge,Scope,Spraak
+Keywords[ne]=मद्दत,HTML, खोजी, अनुक्रमणिका,htdig,htsearch,htmerge, क्षेत्र, भाषा
+Keywords[nl]=help,html,zoeken,index,htdig,htsearch,htmerge,scope,taal
+Keywords[nn]=hjelp,HTML,søk,indeks,htdig,htmerge,område,språk
+Keywords[nso]=Thuso,HTML,Nyako,Palo ya Bangwadi,htdig,htnyako,htmerge,Scope,Leleme
+Keywords[pa]=ਸਹਾਇਤਾ,HTML,Index,htdig,htsearch,htmerge,Scope,ਭਾਸ਼ਾ,ਖੋਜ
+Keywords[pl]=pomoc,HTML,szukaj,indeks,htdig,htsearch,htmerge,zakres,język
+Keywords[pt]=ajuda,html,procura,índice,htdig,htsearch,htmerge,âmbito,língua
+Keywords[pt_BR]=Ajuda,HTML,Procurar,Índice,htdig,htsearch,htmerge,escopo,idioma
+Keywords[ro]=ajutor,HTML,căutare,index,htdig,htsearch,htmerge,domeniu,limbaj
+Keywords[rw]=Ifashayobora,HTML,Ishakisha,htgucukura,htgushakisha,htgukomatanya,Igishushanyombonera,Ururimi
+Keywords[se]=veahkki,HTML,ohcan,indeaksa,indeksa,htdig,htmerge,gaska,giella
+Keywords[sk]=Pomoc,HTML,Hľadať,Katalóg,Index,htdig,htsearch,htmerge,rozsah,jazyk,Pomocník
+Keywords[sl]=Pomoč,HTML,iskanje,indeks,htdig,htsearch,htmerge,doseg,jezik
+Keywords[sr]=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language,помоћ,претрага,индекс,језик,опсег
+Keywords[sr@Latn]=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language,pomoć,pretraga,indeks,jezik,opseg
+Keywords[sv]=Hjälp,HTML,Sök,Index,htdig,htsearch,htmerge,Omfång,Språk
+Keywords[ta]=உதவி,HTML,தேடு,பொருளடக்கம்,htdig,htதேடு,htகல,வரையெல்லை,மொழி
+Keywords[te]=సహాయం,హెచ్ టి ఎంఎల్,అన్వెషణ, సూచిక, హెచ్ టి డిగ్,హెచ్ టి అన్వెషణ,హెచ్ టి కలుపు, లక్ష్యము, భాష.
+Keywords[th]=ช่วยเหลือ,HTML,ค้นหา,ดัชนี,htdig,htsearch,htmerge,Scope,ภาษา
+Keywords[tr]=Yardım,HTML,Ara,İndeks,htdig,htmerge,Dil
+Keywords[uk]=довідка,HTML,пошук,індекс,htdig,контекст,мова,htsearch,htmerge
+Keywords[uz]=Yordam,HTML,Qidirish,Indeks,htdig,htsearch,htmerge,Til
+Keywords[uz@cyrillic]=Ёрдам,HTML,Қидириш,Индекс,htdig,htsearch,htmerge,Тил
+Keywords[ven]=Thuso,HTML,Toda,Mafhelelo,bwa ha ht,toda ha ht,thanganyo ya ht,zwaphanda,luambo
+Keywords[vi]=Trợ giúp,HTML,Tìm kiếm,danh sách,htdig,htsearch,htmerge,Phạm vi,Ngôn ngữ
+Keywords[wa]=Aide,Aidance,HTML,Trover,Indecse,htdig,htsearch,htmerge,Scope,Lingaedje
+Keywords[xh]=Uncedo,HTML,Phendla,Isalathiso,htdig,htsearch,htmerge,Scope,Ulwimi
+Keywords[zh_CN]=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language,帮助,查找,索引,范围,语言
+Keywords[zh_TW]=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language,求助,搜尋,索引,語言
+Keywords[zu]=Usizo,HTML,Usesho,Uhlelo lokuqukethwe,htdig,htsearch,htmerge, Indawo elinganiselwe,Ulimi
+Categories=Qt;KDE;X-KDE-settings-system;
diff --git a/khelpcenter/htmlsearch/htmlsearch.h b/khelpcenter/htmlsearch/htmlsearch.h
new file mode 100644
index 00000000..f5568218
--- /dev/null
+++ b/khelpcenter/htmlsearch/htmlsearch.h
@@ -0,0 +1,64 @@
+#ifndef __HTMLSEARCH_H__
+#define __HTMLSEARCH_H__
+
+
+#include <qstring.h>
+#include <qstringlist.h>
+
+
+class QWidget;
+class QProgressDialog;
+
+
+class KProcess;
+
+
+class ProgressDialog;
+
+
+class HTMLSearch : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ HTMLSearch();
+
+ bool generateIndex(QString lang, QWidget *parent=0);
+
+ QString search(QString lang, QString words, QString method="and", int matches=10,
+ QString format="builtin-long", QString sort="score");
+
+
+protected slots:
+
+ void htdigStdout(KProcess *proc, char *buffer, int buflen);
+ void htdigExited(KProcess *proc);
+ void htmergeExited(KProcess *proc);
+ void htsearchStdout(KProcess *proc, char *buffer, int buflen);
+ void htsearchExited(KProcess *proc);
+
+
+protected:
+
+ QString dataPath(const QString& lang);
+
+ bool saveFilesList(const QString& lang);
+ void scanDir(const QString& dir);
+
+ bool createConfig(const QString& lang);
+
+
+private:
+
+ QStringList _files;
+ KProcess *_proc;
+ int _filesToDig, _filesDigged, _filesScanned;
+ volatile bool _htdigRunning, _htmergeRunning, _htsearchRunning;
+ QString _searchResult;
+ ProgressDialog *progress;
+
+};
+
+
+#endif
diff --git a/khelpcenter/htmlsearch/index.cpp b/khelpcenter/htmlsearch/index.cpp
new file mode 100644
index 00000000..54514558
--- /dev/null
+++ b/khelpcenter/htmlsearch/index.cpp
@@ -0,0 +1,31 @@
+
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <kglobal.h>
+#include <kapplication.h>
+
+#include "htmlsearch.h"
+
+static KCmdLineOptions options[] =
+{
+ { "lang <lang>", I18N_NOOP("The language to index"), "en" },
+ KCmdLineLastOption // End of options.
+};
+
+
+int main(int argc, char *argv[])
+{
+ KAboutData aboutData( "khtmlindex", I18N_NOOP("KHtmlIndex"),
+ "",
+ I18N_NOOP("KDE Index generator for help files."));
+
+ KCmdLineArgs::init(argc, argv, &aboutData);
+ KCmdLineArgs::addCmdLineOptions( options );
+
+ KGlobal::locale()->setMainCatalogue("htmlsearch");
+ KApplication app;
+ HTMLSearch search;
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ search.generateIndex(args->getOption("lang"));
+}
diff --git a/khelpcenter/htmlsearch/kcmhtmlsearch.cpp b/khelpcenter/htmlsearch/kcmhtmlsearch.cpp
new file mode 100644
index 00000000..20ab149b
--- /dev/null
+++ b/khelpcenter/htmlsearch/kcmhtmlsearch.cpp
@@ -0,0 +1,370 @@
+/**
+ * kcmhtmlsearch.cpp
+ *
+ * Copyright (c) 2000 Matthias Hlzer-Klpfel <hoelzer@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <qlayout.h>
+#include <kstandarddirs.h>
+#include <klocale.h>
+#include <kurllabel.h>
+#include <kapplication.h>
+#include <qcheckbox.h>
+#include <qwhatsthis.h>
+#include <kfiledialog.h>
+#include <kprocess.h>
+#include "klangcombo.h"
+#include <kurlrequester.h>
+#include <klineedit.h>
+
+#include "kcmhtmlsearch.moc"
+
+
+KHTMLSearchConfig::KHTMLSearchConfig(QWidget *parent, const char *name)
+ : KCModule(parent, name), indexProc(0)
+{
+ QVBoxLayout *vbox = new QVBoxLayout(this, 5);
+
+
+ QGroupBox *gb = new QGroupBox(i18n("ht://dig"), this);
+ vbox->addWidget(gb);
+
+ QGridLayout *grid = new QGridLayout(gb, 3,2, 6,6);
+
+ grid->addRowSpacing(0, gb->fontMetrics().lineSpacing());
+
+ QLabel *l = new QLabel(i18n("The fulltext search feature makes use of the "
+ "ht://dig HTML search engine. "
+ "You can get ht://dig at the"), gb);
+ l->setAlignment(QLabel::WordBreak);
+ l->setMinimumSize(l->sizeHint());
+ grid->addMultiCellWidget(l, 1, 1, 0, 1);
+ QWhatsThis::add( gb, i18n( "Information about where to get the ht://dig package." ) );
+
+ KURLLabel *url = new KURLLabel(gb);
+ url->setURL("http://www.htdig.org");
+ url->setText(i18n("ht://dig home page"));
+ url->setAlignment(QLabel::AlignHCenter);
+ grid->addMultiCellWidget(url, 2,2, 0, 1);
+ connect(url, SIGNAL(leftClickedURL(const QString&)),
+ this, SLOT(urlClicked(const QString&)));
+
+ gb = new QGroupBox(i18n("Program Locations"), this);
+
+ vbox->addWidget(gb);
+ grid = new QGridLayout(gb, 4,2, 6,6);
+ grid->addRowSpacing(0, gb->fontMetrics().lineSpacing());
+
+ htdigBin = new KURLRequester(gb);
+ l = new QLabel(htdigBin, i18n("ht&dig"), gb);
+ l->setBuddy( htdigBin );
+ grid->addWidget(l, 1,0);
+ grid->addWidget(htdigBin, 1,1);
+ connect(htdigBin->lineEdit(), SIGNAL(textChanged(const QString&)), this, SLOT(configChanged()));
+ QString wtstr = i18n( "Enter the path to your htdig program here, e.g. /usr/local/bin/htdig" );
+ QWhatsThis::add( htdigBin, wtstr );
+ QWhatsThis::add( l, wtstr );
+
+ htsearchBin = new KURLRequester(gb);
+ l = new QLabel(htsearchBin, i18n("ht&search"), gb);
+ l->setBuddy( htsearchBin );
+ grid->addWidget(l, 2,0);
+ grid->addWidget(htsearchBin, 2,1);
+ connect(htsearchBin->lineEdit(), SIGNAL(textChanged(const QString&)), this, SLOT(configChanged()));
+ wtstr = i18n( "Enter the path to your htsearch program here, e.g. /usr/local/bin/htsearch" );
+ QWhatsThis::add( htsearchBin, wtstr );
+ QWhatsThis::add( l, wtstr );
+
+ htmergeBin = new KURLRequester(gb);
+ l = new QLabel(htmergeBin, i18n("ht&merge"), gb);
+ l->setBuddy( htmergeBin );
+ grid->addWidget(l, 3,0);
+ grid->addWidget(htmergeBin, 3,1);
+ connect(htmergeBin->lineEdit(), SIGNAL(textChanged(const QString&)), this, SLOT(configChanged()));
+ wtstr = i18n( "Enter the path to your htmerge program here, e.g. /usr/local/bin/htmerge" );
+ QWhatsThis::add( htmergeBin, wtstr );
+ QWhatsThis::add( l, wtstr );
+
+ QHBoxLayout *hbox = new QHBoxLayout(vbox);
+
+ gb = new QGroupBox(i18n("Scope"), this);
+ hbox->addWidget(gb);
+ QWhatsThis::add( gb, i18n( "Here you can select which parts of the documentation should be included in the fulltext search index. Available options are the KDE Help pages, the installed man pages, and the installed info pages. You can select any number of these." ) );
+
+ QVBoxLayout *vvbox = new QVBoxLayout(gb, 6,2);
+ vvbox->addSpacing(gb->fontMetrics().lineSpacing());
+
+ indexKDE = new QCheckBox(i18n("&KDE help"), gb);
+ vvbox->addWidget(indexKDE);
+ connect(indexKDE, SIGNAL(clicked()), this, SLOT(configChanged()));
+
+ indexMan = new QCheckBox(i18n("&Man pages"), gb);
+ vvbox->addWidget(indexMan);
+ indexMan->setEnabled(false),
+ connect(indexMan, SIGNAL(clicked()), this, SLOT(configChanged()));
+
+ indexInfo = new QCheckBox(i18n("&Info pages"), gb);
+ vvbox->addWidget(indexInfo);
+ indexInfo->setEnabled(false);
+ connect(indexInfo, SIGNAL(clicked()), this, SLOT(configChanged()));
+
+ gb = new QGroupBox(i18n("Additional Search Paths"), this);
+ hbox->addWidget(gb);
+ QWhatsThis::add( gb, i18n( "Here you can add additional paths to search for documentation. To add a path, click on the <em>Add...</em> button and select the folder from where additional documentation should be searched. You can remove folders by clicking on the <em>Delete</em> button." ) );
+
+ grid = new QGridLayout(gb, 4,3, 6,2);
+ grid->addRowSpacing(0, gb->fontMetrics().lineSpacing());
+
+ addButton = new QPushButton(i18n("Add..."), gb);
+ grid->addWidget(addButton, 1,0);
+
+ delButton = new QPushButton(i18n("Delete"), gb);
+ grid->addWidget(delButton, 2,0);
+
+ searchPaths = new KListBox(gb);
+ grid->addMultiCellWidget(searchPaths, 1,3, 1,1);
+ grid->setRowStretch(2,2);
+
+ gb = new QGroupBox(i18n("Language Settings"), this);
+ vbox->addWidget(gb);
+ QWhatsThis::add(gb, i18n("Here you can select the language you want to create the index for."));
+ language = new KLanguageCombo(gb);
+ l = new QLabel(language, i18n("&Language"), gb);
+ vvbox = new QVBoxLayout(gb, 6,2);
+ vvbox->addSpacing(gb->fontMetrics().lineSpacing());
+ hbox = new QHBoxLayout(vvbox, 6);
+ hbox->addWidget(l);
+ hbox->addWidget(language,1);
+ hbox->addStretch(1);
+
+ loadLanguages();
+
+ vbox->addStretch(1);
+
+ runButton = new QPushButton(i18n("Generate Index..."), this);
+ QWhatsThis::add( runButton, i18n( "Click this button to generate the index for the fulltext search." ) );
+ runButton->setFixedSize(runButton->sizeHint());
+ vbox->addWidget(runButton, AlignRight);
+ connect(runButton, SIGNAL(clicked()), this, SLOT(generateIndex()));
+
+ connect(addButton, SIGNAL(clicked()), this, SLOT(addClicked()));
+ connect(delButton, SIGNAL(clicked()), this, SLOT(delClicked()));
+ connect(searchPaths, SIGNAL(highlighted(const QString &)),
+ this, SLOT(pathSelected(const QString &)));
+
+ checkButtons();
+
+ load();
+}
+
+
+void KHTMLSearchConfig::loadLanguages()
+{
+ // clear the list
+ language->clear();
+
+ // add all languages to the list
+ QStringList langs = KGlobal::dirs()->findAllResources("locale",
+ QString::fromLatin1("*/entry.desktop"));
+ langs.sort();
+
+ for (QStringList::ConstIterator it = langs.begin(); it != langs.end(); ++it)
+ {
+ KSimpleConfig entry(*it);
+ entry.setGroup(QString::fromLatin1("KCM Locale"));
+ QString name = entry.readEntry(QString::fromLatin1("Name"), KGlobal::locale()->translate("without name"));
+
+ QString path = *it;
+ int index = path.findRev('/');
+ path = path.left(index);
+ index = path.findRev('/');
+ path = path.mid(index+1);
+ language->insertLanguage(path, name);
+ }
+}
+
+
+QString KHTMLSearchConfig::quickHelp() const
+{
+ return i18n( "<h1>Help Index</h1> This configuration module lets you configure the ht://dig engine which can be used for fulltext search in the KDE documentation as well as other system documentation like man and info pages." );
+}
+
+
+void KHTMLSearchConfig::pathSelected(const QString &)
+{
+ checkButtons();
+}
+
+
+void KHTMLSearchConfig::checkButtons()
+{
+
+ delButton->setEnabled(searchPaths->currentItem() >= 0);
+}
+
+
+void KHTMLSearchConfig::addClicked()
+{
+ QString dir = KFileDialog::getExistingDirectory();
+
+ if (!dir.isEmpty())
+ {
+ for (uint i=0; i<searchPaths->count(); ++i)
+ if (searchPaths->text(i) == dir)
+ return;
+ searchPaths->insertItem(dir);
+ configChanged();
+ }
+}
+
+
+void KHTMLSearchConfig::delClicked()
+{
+ searchPaths->removeItem(searchPaths->currentItem());
+ checkButtons();
+ configChanged();
+}
+
+
+KHTMLSearchConfig::~KHTMLSearchConfig()
+{
+}
+
+
+void KHTMLSearchConfig::configChanged()
+{
+ emit changed(true);
+}
+
+
+void KHTMLSearchConfig::load()
+{
+ KConfig *config = new KConfig("khelpcenterrc", true);
+
+ config->setGroup("htdig");
+ htdigBin->lineEdit()->setText(config->readPathEntry("htdig", kapp->dirs()->findExe("htdig")));
+ htsearchBin->lineEdit()->setText(config->readPathEntry("htsearch", kapp->dirs()->findExe("htsearch")));
+ htmergeBin->lineEdit()->setText(config->readPathEntry("htmerge", kapp->dirs()->findExe("htmerge")));
+
+ config->setGroup("Scope");
+ indexKDE->setChecked(config->readBoolEntry("KDE", true));
+ indexMan->setChecked(config->readBoolEntry("Man", false));
+ indexInfo->setChecked(config->readBoolEntry("Info", false));
+
+ QStringList l = config->readPathListEntry("Paths");
+ searchPaths->clear();
+ QStringList::Iterator it;
+ for (it=l.begin(); it != l.end(); ++it)
+ searchPaths->insertItem(*it);
+
+ config->setGroup("Locale");
+ QString lang = config->readEntry("Search Language", KGlobal::locale()->language());
+ language->setCurrentItem(lang);
+
+ emit changed(false);
+}
+
+
+void KHTMLSearchConfig::save()
+{
+ KConfig *config= new KConfig("khelpcenterrc", false);
+
+ config->setGroup("htdig");
+ config->writePathEntry("htdig", htdigBin->lineEdit()->text());
+ config->writePathEntry("htsearch", htsearchBin->lineEdit()->text());
+ config->writePathEntry("htmerge", htmergeBin->lineEdit()->text());
+
+ config->setGroup("Scope");
+ config->writeEntry("KDE", indexKDE->isChecked());
+ config->writeEntry("Man", indexMan->isChecked());
+ config->writeEntry("Info", indexInfo->isChecked());
+
+ QStringList l;
+ for (uint i=0; i<searchPaths->count(); ++i)
+ l.append(searchPaths->text(i));
+ config->writePathEntry("Paths", l);
+
+ config->setGroup("Locale");
+ config->writeEntry("Search Language", language->currentTag());
+
+ config->sync();
+ delete config;
+
+ emit changed(false);
+}
+
+
+void KHTMLSearchConfig::defaults()
+{
+ htdigBin->lineEdit()->setText(kapp->dirs()->findExe("htdig"));
+ htsearchBin->lineEdit()->setText(kapp->dirs()->findExe("htsearch"));
+ htmergeBin->lineEdit()->setText(kapp->dirs()->findExe("htmerge"));
+
+ indexKDE->setChecked(true);
+ indexMan->setChecked(false);
+ indexInfo->setChecked(false);
+
+ searchPaths->clear();
+
+ language->setCurrentItem(KGlobal::locale()->language());
+
+ emit changed(true);
+}
+
+
+void KHTMLSearchConfig::urlClicked(const QString &url)
+{
+ kapp->invokeBrowser(url);
+}
+
+
+void KHTMLSearchConfig::generateIndex()
+{
+ save();
+
+ QString exe = kapp->dirs()->findExe("khtmlindex");
+ if (exe.isEmpty())
+ return;
+
+ delete indexProc;
+
+ indexProc = new KProcess;
+ *indexProc << exe << "--lang" << language->currentTag();
+
+ connect(indexProc, SIGNAL(processExited(KProcess *)),
+ this, SLOT(indexTerminated(KProcess *)));
+
+ runButton->setEnabled(false);
+
+ indexProc->start();
+}
+
+
+void KHTMLSearchConfig::indexTerminated(KProcess *)
+{
+ runButton->setEnabled(true);
+}
+
+
+extern "C"
+{
+ KDE_EXPORT KCModule *create_htmlsearch(QWidget *parent, const char *name)
+ {
+ KGlobal::locale()->insertCatalogue("kcmhtmlsearch");
+ return new KHTMLSearchConfig(parent, name);
+ };
+}
diff --git a/khelpcenter/htmlsearch/kcmhtmlsearch.h b/khelpcenter/htmlsearch/kcmhtmlsearch.h
new file mode 100644
index 00000000..630f5aed
--- /dev/null
+++ b/khelpcenter/htmlsearch/kcmhtmlsearch.h
@@ -0,0 +1,81 @@
+/**
+ * kcmhtmlsearch.h
+ *
+ * Copyright (c) 2000 Matthias Hlzer-Klpfel <hoelzer@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __kcmhtmlsearch_h__
+#define __kcmhtmlsearch_h__
+
+
+#include <kcmodule.h>
+
+
+class QLineEdit;
+class QCheckBox;
+class QPushButton;
+class KListBox;
+class KProcess;
+class KLanguageCombo;
+class KURLRequester;
+
+class KHTMLSearchConfig : public KCModule
+{
+ Q_OBJECT
+
+public:
+
+ KHTMLSearchConfig(QWidget *parent = 0L, const char *name = 0L);
+ virtual ~KHTMLSearchConfig();
+
+ void load();
+ void save();
+ void defaults();
+
+ QString quickHelp() const;
+
+ int buttons();
+
+
+protected slots:
+
+ void configChanged();
+ void addClicked();
+ void delClicked();
+ void pathSelected(const QString &);
+ void urlClicked(const QString&);
+ void generateIndex();
+
+ void indexTerminated(KProcess *proc);
+
+
+private:
+
+ void checkButtons();
+ void loadLanguages();
+
+ KURLRequester *htdigBin, *htsearchBin, *htmergeBin;
+ QCheckBox *indexKDE, *indexMan, *indexInfo;
+ QPushButton *addButton, *delButton, *runButton;
+ KListBox *searchPaths;
+ KLanguageCombo *language;
+
+ KProcess *indexProc;
+
+};
+
+#endif
diff --git a/khelpcenter/htmlsearch/klangcombo.cpp b/khelpcenter/htmlsearch/klangcombo.cpp
new file mode 100644
index 00000000..0b41ea1e
--- /dev/null
+++ b/khelpcenter/htmlsearch/klangcombo.cpp
@@ -0,0 +1,52 @@
+/*
+ * klangcombo.cpp - Adds some methods for inserting languages.
+ *
+ * Copyright (c) 1999-2000 Hans Petter Bieker <bieker@kde.org>
+ *
+ * Requires the Qt widget libraries, available at no cost at
+ * http://www.troll.no/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <qiconset.h>
+
+#include <kstandarddirs.h>
+
+#include "klangcombo.h"
+#include "klangcombo.moc"
+
+KLanguageCombo::~KLanguageCombo ()
+{
+}
+
+KLanguageCombo::KLanguageCombo (QWidget * parent, const char *name)
+ : KTagComboBox(parent, name)
+{
+}
+
+void KLanguageCombo::insertLanguage(const QString& path, const QString& name, const QString& sub, const QString &submenu, int index)
+{
+ QString output = name + QString::fromLatin1(" (") + path + QString::fromLatin1(")");
+ QPixmap flag(locate("locale", sub + path + QString::fromLatin1("/flag.png")));
+ insertItem(QIconSet(flag), output, path, submenu, index);
+}
+
+void KLanguageCombo::changeLanguage(const QString& name, int i)
+{
+ if (i < 0 || i >= count()) return;
+ QString output = name + QString::fromLatin1(" (") + tag(i) + QString::fromLatin1(")");
+ changeItem(output, i);
+}
diff --git a/khelpcenter/htmlsearch/klangcombo.h b/khelpcenter/htmlsearch/klangcombo.h
new file mode 100644
index 00000000..1c556ae6
--- /dev/null
+++ b/khelpcenter/htmlsearch/klangcombo.h
@@ -0,0 +1,47 @@
+/*
+ * klangcombo.h - Adds some methods for inserting languages.
+ *
+ * Copyright (c) 1999-2000 Hans Petter Bieker <bieker@kde.org>
+ *
+ * Requires the Qt widget libraries, available at no cost at
+ * http://www.troll.no/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __KLANGCOMBO_H__
+#define __KLANGCOMBO_H__
+
+#include "ktagcombobox.h"
+
+/*
+ * Extends KTagCombo to support adding and changing languages.
+ *
+ * It has also support for sub menues.
+ */
+class KLanguageCombo : public KTagComboBox
+{
+ Q_OBJECT
+
+public:
+ KLanguageCombo(QWidget *parent=0, const char *name=0);
+ ~KLanguageCombo();
+
+ void insertLanguage(const QString& path, const QString& name, const QString& sub = QString::null, const QString &submenu = QString::null, int index = -1);
+ void changeLanguage(const QString& name, int i);
+};
+
+#endif
diff --git a/khelpcenter/htmlsearch/ktagcombobox.cpp b/khelpcenter/htmlsearch/ktagcombobox.cpp
new file mode 100644
index 00000000..eea4c149
--- /dev/null
+++ b/khelpcenter/htmlsearch/ktagcombobox.cpp
@@ -0,0 +1,252 @@
+/*
+ * ktagcombobox.cpp - A combobox with support for submenues, icons and tags
+ *
+ * Copyright (c) 1999-2000 Hans Petter Bieker <bieker@kde.org>
+ *
+ * Requires the Qt widget libraries, available at no cost at
+ * http://www.troll.no/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#define INCLUDE_MENUITEM_DEF 1
+#include <qpainter.h>
+#include <qpopupmenu.h>
+
+#include <kdebug.h>
+
+#include "ktagcombobox.h"
+#include "ktagcombobox.moc"
+
+KTagComboBox::~KTagComboBox ()
+{
+ delete popup;
+ delete tags;
+}
+
+KTagComboBox::KTagComboBox (QWidget * parent, const char *name)
+ : QComboBox(parent, name),
+ popup(0),
+ old_popup(0)
+{
+ tags = new QStringList;
+
+ clear();
+}
+
+void KTagComboBox::popupMenu()
+{
+ popup->popup( mapToGlobal( QPoint(0,0) ), current );
+}
+
+void KTagComboBox::keyPressEvent( QKeyEvent *e )
+{
+ int c;
+
+ if ( ( e->key() == Key_F4 && e->state() == 0 ) ||
+ ( e->key() == Key_Down && (e->state() & AltButton) ) ||
+ ( e->key() == Key_Space ) ) {
+ if ( count() ) {
+ popup->setActiveItem( current );
+ popupMenu();
+ }
+ return;
+ } else {
+ e->ignore();
+ return;
+ }
+
+ c = currentItem();
+ emit highlighted( c );
+ emit activated( c );
+}
+
+void KTagComboBox::mousePressEvent( QMouseEvent * )
+{
+ popupMenu();
+}
+
+void KTagComboBox::internalActivate( int index )
+{
+ if (current == index) return;
+ current = index;
+ emit activated( index );
+ repaint();
+}
+
+void KTagComboBox::internalHighlight( int index )
+{
+ emit highlighted( index );
+}
+
+void KTagComboBox::clear()
+{
+ tags->clear();
+
+ delete old_popup;
+ old_popup = popup;
+ popup = new QPopupMenu(this);
+ connect( popup, SIGNAL(activated(int)),
+ SLOT(internalActivate(int)) );
+ connect( popup, SIGNAL(highlighted(int)),
+ SLOT(internalHighlight(int)) );
+}
+
+int KTagComboBox::count() const
+{
+ return tags->count();
+}
+
+static inline void checkInsertPos(QPopupMenu *popup, const QString & str, int &index)
+{
+ if (index == -2) index = popup->count();
+ if (index != -1) return;
+
+ int a = 0;
+ int b = popup->count();
+ while (a <= b) {
+ int w = (a + b) / 2;
+
+ int id = popup->idAt(w);
+ int j = str.compare(popup->text(id));
+
+ if (j > 0)
+ a = w + 1;
+ else
+ b = w - 1;
+ }
+
+ index = a; // it doesn't really matter ... a == b here.
+}
+
+static inline QPopupMenu *checkInsertIndex(QPopupMenu *popup, const QStringList *tags, const QString &submenu)
+{
+ int pos = tags->findIndex(submenu);
+
+ QPopupMenu *pi = 0;
+ if (pos != -1)
+ {
+ QMenuItem *p = popup->findItem(pos);
+ pi = p?p->popup():0;
+ }
+ if (!pi) pi = popup;
+
+ return pi;
+}
+
+void KTagComboBox::insertItem(const QIconSet& icon, const QString &text, const QString &tag, const QString &submenu, int index )
+{
+ QPopupMenu *pi = checkInsertIndex(popup, tags, submenu);
+ checkInsertPos(pi, text, index);
+ pi->insertItem(icon, text, count(), index);
+ tags->append(tag);
+}
+
+void KTagComboBox::insertItem(const QString &text, const QString &tag, const QString &submenu, int index )
+{
+ QPopupMenu *pi = checkInsertIndex(popup, tags, submenu);
+ checkInsertPos(pi, text, index);
+ pi->insertItem(text, count(), index);
+ tags->append(tag);
+}
+
+void KTagComboBox::insertSeparator(const QString &submenu, int index)
+{
+ QPopupMenu *pi = checkInsertIndex(popup, tags, submenu);
+ pi->insertSeparator(index);
+ tags->append(QString::null);
+}
+
+void KTagComboBox::insertSubmenu(const QString &text, const QString &tag, const QString &submenu, int index)
+{
+ QPopupMenu *pi = checkInsertIndex(popup, tags, submenu);
+ QPopupMenu *p = new QPopupMenu(pi);
+ checkInsertPos(pi, text, index);
+ pi->insertItem(text, p, count(), index);
+ tags->append(tag);
+ connect( p, SIGNAL(activated(int)),
+ SLOT(internalActivate(int)) );
+ connect( p, SIGNAL(highlighted(int)),
+ SLOT(internalHighlight(int)) );
+}
+
+void KTagComboBox::paintEvent( QPaintEvent * ev)
+{
+ QComboBox::paintEvent(ev);
+
+ QPainter p (this);
+
+ // Text
+ QRect clip(2, 2, width() - 4, height() - 4);
+#if 0
+ if ( hasFocus() && style().guiStyle() != MotifStyle )
+ p.setPen( colorGroup().highlightedText() );
+#endif
+ p.drawText(clip, AlignCenter | SingleLine, popup->text( current ));
+
+ // Icon
+ QIconSet *icon = popup->iconSet( this->current );
+ if (icon) {
+ QPixmap pm = icon->pixmap();
+ p.drawPixmap( 4, (height()-pm.height())/2, pm );
+ }
+}
+
+bool KTagComboBox::containsTag( const QString &str ) const
+{
+ return tags->contains(str) > 0;
+}
+
+QString KTagComboBox::currentTag() const
+{
+ return *tags->at(currentItem());
+}
+
+QString KTagComboBox::tag(int i) const
+{
+ if (i < 0 || i >= count())
+ {
+ kdDebug() << "KTagComboBox::tag(), unknown tag " << i << endl;
+ return QString::null;
+ }
+ return *tags->at(i);
+}
+
+int KTagComboBox::currentItem() const
+{
+ return current;
+}
+
+void KTagComboBox::setCurrentItem(int i)
+{
+ if (i < 0 || i >= count()) return;
+ current = i;
+ repaint();
+}
+
+void KTagComboBox::setCurrentItem(const QString &code)
+{
+ int i = tags->findIndex(code);
+ if (code.isNull())
+ i = 0;
+ if (i != -1)
+ setCurrentItem(i);
+}
+
+void KTagComboBox::setFont( const QFont &font )
+{
+ QComboBox::setFont( font );
+ popup->setFont( font );
+}
diff --git a/khelpcenter/htmlsearch/ktagcombobox.h b/khelpcenter/htmlsearch/ktagcombobox.h
new file mode 100644
index 00000000..28aad2dc
--- /dev/null
+++ b/khelpcenter/htmlsearch/ktagcombobox.h
@@ -0,0 +1,92 @@
+/*
+ * ktagcombobox.h - A combobox with support for submenues, icons and tags
+ *
+ * Copyright (c) 1999-2000 Hans Petter Bieker <bieker@kde.org>
+ *
+ * Requires the Qt widget libraries, available at no cost at
+ * http://www.troll.no/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __KTAGCOMBOBOX_H__
+#define __KTAGCOMBOBOX_H__
+
+#include <qcombobox.h>
+
+class QPopupMenu;
+
+/*
+ * This class should be just like qcombobox, but it should be possible
+ * to have have a QIconSet for each entry, and each entry should have a tag.
+ *
+ * It has also support for sub menues.
+ */
+class KTagComboBox : public QComboBox
+{
+ Q_OBJECT
+
+public:
+ KTagComboBox(QWidget *parent=0, const char *name=0);
+ ~KTagComboBox();
+
+ void insertItem(const QIconSet& icon, const QString &text, const QString &tag, const QString &submenu = QString::null, int index=-1 );
+ void insertItem(const QString &text, const QString &tag, const QString &submenu = QString::null, int index=-1 );
+ void insertSeparator(const QString &submenu = QString::null, int index=-1 );
+ void insertSubmenu(const QString &text, const QString &tag, const QString &submenu = QString::null, int index=-1);
+
+ int count() const;
+ void clear();
+
+ /*
+ * Tag of the selected item
+ */
+ QString currentTag() const;
+ QString tag ( int i ) const;
+ bool containsTag (const QString &str ) const;
+
+ /*
+ * Set the current item
+ */
+ int currentItem() const;
+ void setCurrentItem(int i);
+ void setCurrentItem(const QString &code);
+
+ // widget stuff
+ virtual void setFont( const QFont & );
+
+signals:
+ void activated( int index );
+ void highlighted( int index );
+
+private slots:
+ void internalActivate( int );
+ void internalHighlight( int );
+
+protected:
+ void paintEvent( QPaintEvent * );
+ void mousePressEvent( QMouseEvent * );
+ void keyPressEvent( QKeyEvent *e );
+ void popupMenu();
+
+private:
+ // work space for the new class
+ QStringList *tags;
+ QPopupMenu *popup, *old_popup;
+ int current;
+};
+
+#endif
diff --git a/khelpcenter/htmlsearch/long.html b/khelpcenter/htmlsearch/long.html
new file mode 100644
index 00000000..1d0fa4ce
--- /dev/null
+++ b/khelpcenter/htmlsearch/long.html
@@ -0,0 +1,6 @@
+<dl><dt><strong><a href="$&(URL)">$&(TITLE)</a></strong>$(STARSLEFT)
+</dt><dd>$(EXCERPT)<br>
+<i><a href="$&(URL)">$&(URL)</a></i>
+<font size="-1">$(MODIFIED), $(SIZE) bytes</font>
+</dd></dl>
+
diff --git a/khelpcenter/htmlsearch/meinproc_wrapper b/khelpcenter/htmlsearch/meinproc_wrapper
new file mode 100644
index 00000000..239cf746
--- /dev/null
+++ b/khelpcenter/htmlsearch/meinproc_wrapper
@@ -0,0 +1,4 @@
+#! /bin/sh
+
+file=`echo $3 | sed -e "s#http://localhost/#/#; s#file:/*#/#"`
+meinproc --htdig $file
diff --git a/khelpcenter/htmlsearch/nomatch.html b/khelpcenter/htmlsearch/nomatch.html
new file mode 100644
index 00000000..30592703
--- /dev/null
+++ b/khelpcenter/htmlsearch/nomatch.html
@@ -0,0 +1,21 @@
+<html><head><title>No match for '$&(LOGICAL_WORDS)'</title></head>
+<body bgcolor="#ffffff" text="#000000" link="#aa0000">
+<h1><img src="htdig.gif">
+Search results</h1>
+<hr noshade size="4">
+<h2>No matches were found for '$&(LOGICAL_WORDS)'</h2>
+<p>
+Check the spelling of the search word(s) you used.
+If the spelling is correct and you only used one word,
+try using one or more similar search words with "<b>Any</b>."
+</p><p>
+If the spelling is correct and you used more than one
+word with "<b>Any</b>," try using one or more similar search
+words with "<b>Any</b>."</p><p>
+If the spelling is correct and you used more than one
+word with "<b>All</b>," try using one or more of the same words
+with "<b>Any</b>."</p>
+<hr noshade size="4">
+<a href="http://www.htdig.org/">
+<img src="htdig.gif" border="0">ht://Dig $(VERSION)</a>
+</body></html>
diff --git a/khelpcenter/htmlsearch/progressdialog.cpp b/khelpcenter/htmlsearch/progressdialog.cpp
new file mode 100644
index 00000000..497c9032
--- /dev/null
+++ b/khelpcenter/htmlsearch/progressdialog.cpp
@@ -0,0 +1,76 @@
+#include <qlayout.h>
+#include <qlabel.h>
+
+
+#include <klocale.h>
+#include <kprogress.h>
+#include <kstandarddirs.h>
+
+
+#include "progressdialog.moc"
+
+
+ProgressDialog::ProgressDialog(QWidget *parent, const char *name)
+ : KDialogBase(KDialogBase::Plain, i18n("Generating Index"), Cancel, Cancel,
+ parent, name, false)
+{
+ QGridLayout *grid = new QGridLayout(plainPage(), 5,3, spacingHint());
+
+ QLabel *l = new QLabel(i18n("Scanning for files"), plainPage());
+ grid->addMultiCellWidget(l, 0,0, 1,2);
+
+ filesScanned = new QLabel(plainPage());
+ grid->addWidget(filesScanned, 1,2);
+ setFilesScanned(0);
+
+ check1 = new QLabel(plainPage());
+ grid->addWidget(check1, 0,0);
+
+ l = new QLabel(i18n("Extracting search terms"), plainPage());
+ grid->addMultiCellWidget(l, 2,2, 1,2);
+
+ bar = new KProgress(plainPage());
+ grid->addWidget(bar, 3,2);
+
+ check2 = new QLabel(plainPage());
+ grid->addWidget(check2, 2,0);
+
+ l = new QLabel(i18n("Generating index..."), plainPage());
+ grid->addMultiCellWidget(l, 4,4, 1,2);
+
+ check3 = new QLabel(plainPage());
+ grid->addWidget(check3, 4,0);
+
+ setState(0);
+
+ setMinimumWidth(300);
+}
+
+
+void ProgressDialog::setFilesScanned(int n)
+{
+ filesScanned->setText(i18n("Files processed: %1").arg(n));
+}
+
+
+void ProgressDialog::setFilesToDig(int n)
+{
+ bar->setTotalSteps(n);
+}
+
+
+void ProgressDialog::setFilesDigged(int n)
+{
+ bar->setProgress(n);
+}
+
+
+void ProgressDialog::setState(int n)
+{
+ QPixmap unchecked = QPixmap(locate("data", "khelpcenter/pics/unchecked.xpm"));
+ QPixmap checked = QPixmap(locate("data", "khelpcenter/pics/checked.xpm"));
+
+ check1->setPixmap( n > 0 ? checked : unchecked);
+ check2->setPixmap( n > 1 ? checked : unchecked);
+ check3->setPixmap( n > 2 ? checked : unchecked);
+}
diff --git a/khelpcenter/htmlsearch/progressdialog.h b/khelpcenter/htmlsearch/progressdialog.h
new file mode 100644
index 00000000..9c18f2d0
--- /dev/null
+++ b/khelpcenter/htmlsearch/progressdialog.h
@@ -0,0 +1,35 @@
+#ifndef __PROGRESS_DIALOG_H__
+#define __PROGRESS_DIALOG_H__
+
+
+#include <kdialogbase.h>
+
+
+class QLabel;
+class KProgress;
+
+
+class ProgressDialog : public KDialogBase
+{
+
+ Q_OBJECT
+
+public:
+
+ ProgressDialog(QWidget *parent=0, const char *name=0);
+
+ void setFilesScanned(int s);
+ void setFilesToDig(int d);
+ void setFilesDigged(int d);
+
+ void setState(int n);
+
+private:
+
+ QLabel *filesScanned, *check1, *check2, *check3;
+ KProgress *bar;
+
+};
+
+
+#endif
diff --git a/khelpcenter/htmlsearch/short.html b/khelpcenter/htmlsearch/short.html
new file mode 100644
index 00000000..e3e5e447
--- /dev/null
+++ b/khelpcenter/htmlsearch/short.html
@@ -0,0 +1 @@
+$(STARSRIGHT) <strong><a href="$&(URL)">$&(TITLE)</a></strong><br>
diff --git a/khelpcenter/htmlsearch/star.png b/khelpcenter/htmlsearch/star.png
new file mode 100644
index 00000000..5e761587
--- /dev/null
+++ b/khelpcenter/htmlsearch/star.png
Binary files differ
diff --git a/khelpcenter/htmlsearch/star_blank.png b/khelpcenter/htmlsearch/star_blank.png
new file mode 100644
index 00000000..2689281a
--- /dev/null
+++ b/khelpcenter/htmlsearch/star_blank.png
Binary files differ
diff --git a/khelpcenter/htmlsearch/syntax.html b/khelpcenter/htmlsearch/syntax.html
new file mode 100644
index 00000000..e724fd90
--- /dev/null
+++ b/khelpcenter/htmlsearch/syntax.html
@@ -0,0 +1,19 @@
+<html><head><title>Error in Boolean search for '$&(WORDS)'</title></head>
+<body bgcolor="#ffffff" text="#000000" link="#aa0000">
+<h1><img src="htdig.gif">
+Error in Boolean search for '$&(LOGICAL_WORDS)'</h1>
+<hr noshade size="4">
+Boolean expressions need to be 'correct' in order for the search
+system to use them.
+The expression you entered has errors in it.<p>
+Examples of correct expressions are: <b>cat and dog</b>, <b>cat
+not dog</b>, <b>cat or (dog not nose)</b>.<br>Note that
+the operator <b>not</b> has the meaning of 'without'.
+<blockquote><b>
+$(SYNTAXERROR)
+</b></blockquote>
+<hr noshade size="4">
+<a href="http://www.htdig.org/">
+<img src="htdig.gif" border="0">ht://Dig $(VERSION)</a>
+</body></html>
+
diff --git a/khelpcenter/htmlsearch/unchecked.xpm b/khelpcenter/htmlsearch/unchecked.xpm
new file mode 100644
index 00000000..e447281a
--- /dev/null
+++ b/khelpcenter/htmlsearch/unchecked.xpm
@@ -0,0 +1,22 @@
+/* XPM */
+static char*unchecked[]={
+"16 16 3 1",
+"# c #000000",
+"+ c #ffffff",
+". c None",
+"................",
+"................",
+"..++++++++++++..",
+"..+##########+..",
+"..+#++++++++#+..",
+"..+#+......+#+..",
+"..+#+......+#+..",
+"..+#+......+#+..",
+"..+#+......+#+..",
+"..+#+......+#+..",
+"..+#+......+#+..",
+"..+#++++++++#+..",
+"..+##########+..",
+"..++++++++++++..",
+"................",
+"................"};
diff --git a/khelpcenter/htmlsearch/wrapper.html b/khelpcenter/htmlsearch/wrapper.html
new file mode 100644
index 00000000..251266de
--- /dev/null
+++ b/khelpcenter/htmlsearch/wrapper.html
@@ -0,0 +1,16 @@
+<html><head><title>Search results for '$&(WORDS)'</title></head>
+<body bgcolor="#ffffff" text="#000000" link="#aa0000">
+<h2><img src="htdig.gif">
+Search results for '$&(LOGICAL_WORDS)'</h2>
+<hr noshade size="4">
+<b>
+More <img src="reload.png" alt="*">'s indicate a better match.
+</b>
+<hr noshade size="1">
+$(HTSEARCH_RESULTS)
+$(PAGEHEADER)
+$(PREVPAGE) $(PAGELIST) $(NEXTPAGE)
+<hr noshade size="4">
+<a href="http://www.htdig.org/">
+<img src="htdig.gif" border="0">ht://Dig $(VERSION)</a>
+</body></html>
diff --git a/khelpcenter/htmlsearchconfig.cpp b/khelpcenter/htmlsearchconfig.cpp
new file mode 100644
index 00000000..999deb27
--- /dev/null
+++ b/khelpcenter/htmlsearchconfig.cpp
@@ -0,0 +1,151 @@
+/**
+ * kcmhtmlsearch.cpp
+ *
+ * Copyright (c) 2000 Matthias Hlzer-Klpfel <hoelzer@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <qlayout.h>
+#include <qwhatsthis.h>
+
+#include <kdebug.h>
+#include <kstandarddirs.h>
+#include <klocale.h>
+#include <kurllabel.h>
+#include <kapplication.h>
+#include <kfiledialog.h>
+#include <kurlrequester.h>
+#include <klineedit.h>
+
+#include "htmlsearchconfig.h"
+#include "htmlsearchconfig.moc"
+
+namespace KHC {
+
+HtmlSearchConfig::HtmlSearchConfig(QWidget *parent, const char *name)
+ : QWidget(parent, name)
+{
+ QVBoxLayout *vbox = new QVBoxLayout(this, 5);
+
+
+ QGroupBox *gb = new QGroupBox(i18n("ht://dig"), this);
+ vbox->addWidget(gb);
+
+ QGridLayout *grid = new QGridLayout(gb, 3,2, 6,6);
+
+ grid->addRowSpacing(0, gb->fontMetrics().lineSpacing());
+
+ QLabel *l = new QLabel(i18n("The fulltext search feature makes use of the "
+ "ht://dig HTML search engine. "
+ "You can get ht://dig at the"), gb);
+ l->setAlignment(QLabel::WordBreak);
+ l->setMinimumSize(l->sizeHint());
+ grid->addMultiCellWidget(l, 1, 1, 0, 1);
+ QWhatsThis::add( gb, i18n( "Information about where to get the ht://dig package." ) );
+
+ KURLLabel *url = new KURLLabel(gb);
+ url->setURL("http://www.htdig.org");
+ url->setText(i18n("ht://dig home page"));
+ url->setAlignment(QLabel::AlignHCenter);
+ grid->addMultiCellWidget(url, 2,2, 0, 1);
+ connect(url, SIGNAL(leftClickedURL(const QString&)),
+ this, SLOT(urlClicked(const QString&)));
+
+ gb = new QGroupBox(i18n("Program Locations"), this);
+
+ vbox->addWidget(gb);
+ grid = new QGridLayout(gb, 4,2, 6,6);
+ grid->addRowSpacing(0, gb->fontMetrics().lineSpacing());
+
+ mHtsearchUrl = new KURLRequester(gb);
+ l = new QLabel(mHtsearchUrl, i18n("htsearch:"), gb);
+ l->setBuddy( mHtsearchUrl );
+ grid->addWidget(l, 1,0);
+ grid->addWidget(mHtsearchUrl, 1,1);
+ connect( mHtsearchUrl->lineEdit(), SIGNAL( textChanged( const QString & ) ),
+ SIGNAL( changed() ) );
+ QString wtstr = i18n( "Enter the URL of the htsearch CGI program." );
+ QWhatsThis::add( mHtsearchUrl, wtstr );
+ QWhatsThis::add( l, wtstr );
+
+ mIndexerBin = new KURLRequester(gb);
+ l = new QLabel(mIndexerBin, i18n("Indexer:"), gb);
+ l->setBuddy( mIndexerBin );
+ grid->addWidget(l, 2,0);
+ grid->addWidget(mIndexerBin, 2,1);
+ connect( mIndexerBin->lineEdit(), SIGNAL( textChanged( const QString & ) ),
+ SIGNAL( changed() ) );
+ wtstr = i18n( "Enter the path to your htdig indexer program here." );
+ QWhatsThis::add( mIndexerBin, wtstr );
+ QWhatsThis::add( l, wtstr );
+
+ mDbDir = new KURLRequester(gb);
+ mDbDir->setMode( KFile::Directory | KFile::LocalOnly );
+ l = new QLabel(mDbDir, i18n("htdig database:"), gb);
+ l->setBuddy( mDbDir );
+ grid->addWidget(l, 3,0);
+ grid->addWidget(mDbDir, 3,1);
+ connect( mDbDir->lineEdit(), SIGNAL( textChanged( const QString & ) ),
+ SIGNAL( changed() ) );
+ wtstr = i18n( "Enter the path to the htdig database folder." );
+ QWhatsThis::add( mDbDir, wtstr );
+ QWhatsThis::add( l, wtstr );
+}
+
+HtmlSearchConfig::~HtmlSearchConfig()
+{
+ kdDebug() << "~HtmlSearchConfig()" << endl;
+}
+
+void HtmlSearchConfig::makeReadOnly()
+{
+ mHtsearchUrl->setEnabled( false );
+ mIndexerBin->setEnabled( false );
+ mDbDir->setEnabled( false );
+}
+
+void HtmlSearchConfig::load( KConfig *config )
+{
+ config->setGroup("htdig");
+
+ mHtsearchUrl->lineEdit()->setText(config->readPathEntry("htsearch", kapp->dirs()->findExe("htsearch")));
+ mIndexerBin->lineEdit()->setText(config->readPathEntry("indexer"));
+ mDbDir->lineEdit()->setText(config->readPathEntry("dbdir", "/opt/www/htdig/db/" ) );
+}
+
+void HtmlSearchConfig::save( KConfig *config )
+{
+ config->setGroup("htdig");
+
+ config->writePathEntry("htsearch", mHtsearchUrl->lineEdit()->text());
+ config->writePathEntry("indexer", mIndexerBin->lineEdit()->text());
+ config->writePathEntry("dbdir", mDbDir->lineEdit()->text());
+}
+
+void HtmlSearchConfig::defaults()
+{
+ mHtsearchUrl->lineEdit()->setText(kapp->dirs()->findExe("htsearch"));
+ mIndexerBin->lineEdit()->setText("");
+ mDbDir->lineEdit()->setText("/opt/www/htdig/db/" );
+}
+
+void HtmlSearchConfig::urlClicked(const QString &url)
+{
+ kapp->invokeBrowser(url);
+}
+
+} // End namespace KHC
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/htmlsearchconfig.h b/khelpcenter/htmlsearchconfig.h
new file mode 100644
index 00000000..bd3b2f27
--- /dev/null
+++ b/khelpcenter/htmlsearchconfig.h
@@ -0,0 +1,58 @@
+/**
+ * This file is part of KHelpCenter
+ *
+ * Copyright (c) 2000 Matthias Hlzer-Klpfel <hoelzer@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KHC_HTMLSEARCHCONFIG_H
+#define KHC_HTMLSEARCHCONFIG_H
+
+#include <qwidget.h>
+
+class KURLRequester;
+class KConfig;
+
+namespace KHC {
+
+class HtmlSearchConfig : public QWidget
+{
+ Q_OBJECT
+ public:
+ HtmlSearchConfig(QWidget *parent = 0L, const char *name = 0L);
+ virtual ~HtmlSearchConfig();
+
+ void load( KConfig * );
+ void save( KConfig * );
+ void defaults();
+ void makeReadOnly();
+
+ signals:
+ void changed();
+
+ protected slots:
+ void urlClicked(const QString&);
+
+ private:
+ KURLRequester *mHtsearchUrl;
+ KURLRequester *mIndexerBin;
+ KURLRequester *mDbDir;
+};
+
+}
+
+#endif
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/index.html.in b/khelpcenter/index.html.in
new file mode 100644
index 00000000..9e2a4462
--- /dev/null
+++ b/khelpcenter/index.html.in
@@ -0,0 +1,42 @@
+<html>
+
+ <head>
+ <title>%1</title>
+ <link rel="stylesheet" href="help:/common/kde-default.css" type="text/css" />
+ </head>
+
+ <body>
+ <div style="background-image: url(help:/common/top-middle.png); width: 100%; height: 131px;">
+ <div style="position: absolute; right: 0px;">
+ <img src="help:/common/top-right-konqueror.png" style="margin: 0px" alt="">
+ </div>
+ <div style="position: absolute; left: 0px;">
+ <img src="help:/common/top-left.png" style="margin: 0px" alt="">
+ </div>
+ <div style="position: absolute;
+ top: 25px;
+ right: 100px;
+ text-align: right;
+ font-size: xx-large;
+ font-weight: bold;
+ text-shadow: #fff 0px 0px 5px;
+ color: #444">
+ %2
+ </div>
+ </div>
+ %3
+ <div class="bannerBottom" style="background-image: url(help:/common/bottom-middle.png);
+ background-repeat: x-repeat;
+ width: 100%;
+ height: 100px;
+ bottom:0px;">
+ <div class="bannerBottomRight">
+ <img src="help:/common/bottom-right.png" style="margin: 0px" alt="">
+ </div>
+ <div class="bannerBottomLeft">
+ <img src="help:/common/bottom-left.png" style="margin: 0px;" alt="">
+ </div>
+ </div>
+ </body>
+
+</html>
diff --git a/khelpcenter/infotree.cpp b/khelpcenter/infotree.cpp
new file mode 100644
index 00000000..61f44a10
--- /dev/null
+++ b/khelpcenter/infotree.cpp
@@ -0,0 +1,184 @@
+/*
+ * This file is part of the KDE Help Center
+ *
+ * Copyright (C) 2002 Frerich Raabe (raabe@kde.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "infotree.h"
+
+#include "navigatoritem.h"
+#include "docentry.h"
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <klistview.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <kurl.h>
+
+#include <qfile.h>
+#include <qtextstream.h>
+
+#include <stdlib.h> // for getenv()
+
+using namespace KHC;
+
+class InfoCategoryItem : public NavigatorItem
+{
+ public:
+ InfoCategoryItem( NavigatorItem *parent, const QString &text );
+
+ virtual void setOpen( bool open );
+};
+
+class InfoNodeItem : public NavigatorItem
+{
+ public:
+ InfoNodeItem( InfoCategoryItem *parent, const QString &text );
+};
+
+InfoCategoryItem::InfoCategoryItem( NavigatorItem *parent, const QString &text )
+ : NavigatorItem( new DocEntry( text ), parent )
+{
+ setAutoDeleteDocEntry( true );
+ setOpen( false );
+// kdDebug(1400) << "Got category: " << text << endl;
+}
+
+void InfoCategoryItem::setOpen( bool open )
+{
+ NavigatorItem::setOpen( open );
+
+ if ( open && childCount() > 0 ) setPixmap( 0, SmallIcon( "contents" ) );
+ else setPixmap( 0, SmallIcon( "contents2" ) );
+}
+
+InfoNodeItem::InfoNodeItem( InfoCategoryItem *parent, const QString &text )
+ : NavigatorItem( new DocEntry( text ), parent )
+{
+ setAutoDeleteDocEntry( true );
+// kdDebug( 1400 ) << "Created info node item: " << text << endl;
+}
+
+InfoTree::InfoTree( QObject *parent, const char *name )
+ : TreeBuilder( parent, name ),
+ m_parentItem( 0 )
+{
+}
+
+void InfoTree::build( NavigatorItem *parent )
+{
+ kdDebug( 1400 ) << "Populating info tree." << endl;
+
+ m_parentItem = parent;
+
+ DocEntry *entry = new DocEntry( i18n( "Alphabetically" ) );
+ m_alphabItem = new NavigatorItem( entry, parent );
+ m_alphabItem->setAutoDeleteDocEntry( true );
+ entry = new DocEntry( i18n( "By Category" ) );
+ m_categoryItem = new NavigatorItem( entry, parent );
+ m_categoryItem->setAutoDeleteDocEntry( true );
+
+ KConfig *cfg = kapp->config();
+ cfg->setGroup( "Info pages" );
+ QStringList infoDirFiles = cfg->readListEntry( "Search paths" );
+ // Default paths taken fron kdebase/kioslave/info/kde-info2html.conf
+ if ( infoDirFiles.isEmpty() ) {
+ infoDirFiles << "/usr/share/info";
+ infoDirFiles << "/usr/info";
+ infoDirFiles << "/usr/lib/info";
+ infoDirFiles << "/usr/local/info";
+ infoDirFiles << "/usr/local/lib/info";
+ infoDirFiles << "/usr/X11R6/info";
+ infoDirFiles << "/usr/X11R6/lib/info";
+ infoDirFiles << "/usr/X11R6/lib/xemacs/info";
+ }
+
+ QString infoPath = ::getenv( "INFOPATH" );
+ if ( !infoPath.isEmpty() )
+ infoDirFiles += QStringList::split( ':', infoPath );
+
+ QStringList::ConstIterator it = infoDirFiles.begin();
+ QStringList::ConstIterator end = infoDirFiles.end();
+ for ( ; it != end; ++it ) {
+ QString infoDirFileName = *it + "/dir";
+ if ( QFile::exists( infoDirFileName ) )
+ parseInfoDirFile( infoDirFileName );
+ }
+
+ m_alphabItem->sortChildItems( 0, true /* ascending */ );
+}
+
+void InfoTree::parseInfoDirFile( const QString &infoDirFileName )
+{
+ kdDebug( 1400 ) << "Parsing info dir file " << infoDirFileName << endl;
+
+ QFile infoDirFile( infoDirFileName );
+ if ( !infoDirFile.open( IO_ReadOnly ) )
+ return;
+
+ QTextStream stream( &infoDirFile );
+ // Skip introduction blurb.
+ while ( !stream.eof() && !stream.readLine().startsWith( "* Menu:" ) );
+
+ while ( !stream.eof() ) {
+ QString s = stream.readLine();
+ if ( s.stripWhiteSpace().isEmpty() )
+ continue;
+
+ InfoCategoryItem *catItem = new InfoCategoryItem( m_categoryItem, s );
+ while ( !stream.eof() && !s.stripWhiteSpace().isEmpty() ) {
+ s = stream.readLine();
+ if ( s[ 0 ] == '*' ) {
+ const int colon = s.find( ":" );
+ const int openBrace = s.find( "(", colon );
+ const int closeBrace = s.find( ")", openBrace );
+ const int dot = s.find( ".", closeBrace );
+
+ QString appName = s.mid( 2, colon - 2 );
+ QString url = "info:/" + s.mid( openBrace + 1, closeBrace - openBrace - 1 );
+ if ( dot - closeBrace > 1 )
+ url += "/" + s.mid( closeBrace + 1, dot - closeBrace - 1 );
+ else
+ url += "/Top";
+
+ InfoNodeItem *item = new InfoNodeItem( catItem, appName );
+ item->entry()->setUrl( url );
+
+ InfoCategoryItem *alphabSection = 0;
+ for ( QListViewItem* it=m_alphabItem->firstChild(); it; it=it->nextSibling() ) {
+ if ( it->text( 0 ) == appName[ 0 ].upper() ) {
+ alphabSection = static_cast<InfoCategoryItem *>( it );
+ break;
+ }
+ }
+
+ if ( alphabSection == 0 )
+ alphabSection = new InfoCategoryItem( m_alphabItem, appName[ 0 ].upper() );
+
+ item = new InfoNodeItem( alphabSection, appName );
+ item->entry()->setUrl( url );
+ }
+ }
+ }
+ infoDirFile.close();
+}
+
+#include "infotree.moc"
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/infotree.h b/khelpcenter/infotree.h
new file mode 100644
index 00000000..a7f2c5c5
--- /dev/null
+++ b/khelpcenter/infotree.h
@@ -0,0 +1,48 @@
+/*
+ * infotree.h - part of the KDE Help Center
+ *
+ * Copyright (C) 2002 Frerich Raabe (raabe@kde.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef KHC_INFOTREE_H
+#define KHC_INFOTREE_H
+
+#include "treebuilder.h"
+
+class QListViewItem;
+
+namespace KHC
+{
+ class NavigatorItem;
+ class InfoTree : public TreeBuilder
+ {
+ Q_OBJECT
+ public:
+ InfoTree( QObject *parent, const char *name = 0 );
+
+ virtual void build( NavigatorItem *parentItem );
+
+ private:
+ void parseInfoDirFile( const QString &fileName );
+
+ NavigatorItem *m_parentItem;
+ NavigatorItem *m_alphabItem;
+ NavigatorItem *m_categoryItem;
+ };
+}
+
+#endif // KHC_INFOTREE_H
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/intro.html.in b/khelpcenter/intro.html.in
new file mode 100644
index 00000000..66ec04cc
--- /dev/null
+++ b/khelpcenter/intro.html.in
@@ -0,0 +1,141 @@
+<HTML>
+
+<HEAD>
+ <title>%1</title>
+ <link rel="stylesheet" href="file:%1" type="text/css" />
+</HEAD>
+
+<BODY BGCOLOR=#3679AD LEFTMARGIN=0 TOPMARGIN=5>
+<div style="position:absolute; left: 0px; top: 5px; right: 0px; bottom: 500px;">
+<TABLE BORDER=0 WIDTH=100% CELLPADDING=0 CELLSPACING=0 CELLPADDING=0>
+ <COLGROUP>
+ <COL WIDTH=156>
+ <COL WIDTH=20>
+ <COL WIDTH=282>
+ <COL WIDTH=*>
+ </COLGROUP>
+ <TR HEIGHT=24>
+ <TD BGCOLOR=#505050 ALIGN=RIGHT><IMG WIDTH=70 HEIGHT=22 SRC="file:%1"></TD>
+ <TD BGCOLOR=#505050 COLSPAN=3></TD>
+ </TR>
+ <TR>
+ <TD WIDTH=176 COLSPAN=2 ROWSPAN=2> &nbsp;</TD>
+ <TD CLASS="caption" ALIGN="center" WIDTH=282 HEIGHT=77 BACKGROUND="file:%1">%1</TD>
+ <TD BGCOLOR=#DDDDDD BACKGROUND="file:%1">&nbsp;</TD>
+ </TR>
+
+ <TR>
+
+ <TD COLSPAN=2 BGCOLOR=#505050 ALIGN=RIGHT HEIGHT=22>
+
+<TABLE BORDER=0 CELLPADDING=0 CELLSPACING=0 CELLPADDING=0>
+ <TR>
+ <TD HEIGHT=20 class="menu">&nbsp;</TD>
+ </TR>
+</TABLE>
+ </TD>
+ </TR>
+
+ <TR>
+ <TD COLSPAN=2 WIDTH=176></TD>
+ <TD COLSPAN=2 class="shadow1" HEIGHT=9 COLSPAN=4></TD>
+ </TR>
+ <TR>
+ <TD COLSPAN=2 WIDTH=176></TD>
+ <TD COLSPAN=2 HEIGHT=46 COLSPAN=4></TD>
+ </TR>
+</TABLE>
+
+<!-- end of header -->
+
+
+<TABLE WIDTH=100% BORDER=0 CELLPADDING=0 CELLSPACING=0 CELLPADDING=0>
+<TR>
+ <TD WIDTH=114></TD>
+ <TD class="trans" BGCOLOR=#D0DFEC>
+
+ <TABLE WIDTH= 100% BORDER=0 CELLPADDING=0 CELLSPACING=0 CELLPADDING=0>
+ <TR>
+ <TD HEIGHT=20 WIDTH=20>&nbsp;</TD>
+ <TD>&nbsp;</TD>
+ </TR>
+ <TR>
+ <TD WIDTH=20>&nbsp;</TD>
+ <TD VALIGN=TOP>
+
+<!-- here comes the content -->
+
+
+<h1>%1</h1> <!-- Welcome to the K Desktop Environment -->
+
+<p><i>%1</i></p> <!-- The KDE team welcomes you to user-friendly UNIX computing -->
+
+<p>%1</p><!-- KDE is a powerful graphical desktop environment for Unix workstations. A
+KDE desktop combines ease of use, contemporary functionality and outstanding
+graphical design with the technological superiority of the Unix operating
+system. -->
+
+<ul>
+<li><p><a href="help:/khelpcenter/index.html?anchor=whatiskde">%1</a></p></li>
+<li><p><a href="help:/khelpcenter/index.html?anchor=contact">%1</a></p></li> <!-- Contacting the KDE Project -->
+<li><p><a href="help:/khelpcenter/index.html?anchor=support">%1</a></p></li> <!-- Supporting the KDE Project -->
+<li><p><a href="help:/khelpcenter/index.html?anchor=links">%1</a></p></li> <!-- Useful links -->
+</ul>
+
+<h2>%1</h2> <!-- Getting the most out of KDE -->
+
+<h3>%1</h3> <!-- General Documentation -->
+
+<ul>
+<li><p><a href="help:/khelpcenter/quickstart/index.html" target="_top">%1</a></p></li>
+<li><p><a href="help:/khelpcenter/userguide/index.html" target="_top">%1</a></p></li>
+<li><p><a href="help:/khelpcenter/faq/index.html" target="_top">%1</a></p></li>
+</ul>
+
+<h3>%1</h3>
+
+<ul>
+<li><p><a href="help:/kicker/index.html" target="_top">%1</a></p></li>
+<li><p><a href="help:/kcontrol/index.html" target="_top">%1</a></p></li>
+<li><p><a href="help:/konqueror/index.html" target="_top">%1</a></p></li>
+</ul>
+
+
+
+
+
+<!-- End of text -->
+
+
+ </TD>
+ <TD WIDTH=20>&nbsp;</TD>
+ </TR>
+ <TR>
+ <TD HEIGHT=20 WIDTH=20>&nbsp;</TD>
+ <TD>&nbsp;</TD>
+ </TR>
+
+</TABLE>
+
+ </TD>
+ <TD WIDTH=20>&nbsp;</TD>
+ </TR>
+ <TR>
+ <TD HEIGHT=44 COLSPAN=3>&nbsp;</TD>
+ </TR>
+</TR>
+</TABLE>
+<TABLE WIDTH=100% BORDER=0 CELLSPACING=0 CELLPADDING=0>
+<TR>
+<TD class="end" WIDTH=*>&nbsp;</TD>
+<TD WIDTH=204><A HREF="http://www.kde.org"> <IMG WIDTH=204 BORDER=0
+HEIGHT=57
+SRC="file:%1"></A></TD>
+</TR>
+<TR>
+ <TD HEIGHT=50 COLSPAN=2>&nbsp;</TD>
+</TR>
+</TABLE>
+</div>
+</BODY>
+</HTML>
diff --git a/khelpcenter/kcmhelpcenter.cpp b/khelpcenter/kcmhelpcenter.cpp
new file mode 100644
index 00000000..3c122b3b
--- /dev/null
+++ b/khelpcenter/kcmhelpcenter.cpp
@@ -0,0 +1,680 @@
+/*
+ This file is part of KHelpcenter.
+
+ Copyright (C) 2002 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This program 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kcmhelpcenter.h"
+
+#include "htmlsearchconfig.h"
+#include "docmetainfo.h"
+#include "prefs.h"
+#include "searchhandler.h"
+#include "searchengine.h"
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kaboutdata.h>
+#include <kdialog.h>
+#include <kstandarddirs.h>
+#include <kprocess.h>
+#include <kapplication.h>
+#include <dcopclient.h>
+#include <ktempfile.h>
+#include <kurlrequester.h>
+#include <kmessagebox.h>
+#include <klistview.h>
+#include <klineedit.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qdir.h>
+#include <qtabwidget.h>
+#include <qprogressbar.h>
+#include <qfile.h>
+#include <qlabel.h>
+#include <qvbox.h>
+#include <qtextedit.h>
+#include <qregexp.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+
+using namespace KHC;
+
+IndexDirDialog::IndexDirDialog( QWidget *parent )
+ : KDialogBase( parent, 0, true, i18n("Change Index Folder"), Ok | Cancel )
+{
+ QFrame *topFrame = makeMainWidget();
+
+ QBoxLayout *urlLayout = new QHBoxLayout( topFrame );
+
+ QLabel *label = new QLabel( i18n("Index folder:"), topFrame );
+ urlLayout->addWidget( label );
+
+ mIndexUrlRequester = new KURLRequester( topFrame );
+ mIndexUrlRequester->setMode( KFile::Directory | KFile::ExistingOnly |
+ KFile::LocalOnly );
+ urlLayout->addWidget( mIndexUrlRequester );
+
+ mIndexUrlRequester->setURL( Prefs::indexDirectory() );
+ connect(mIndexUrlRequester->lineEdit(),SIGNAL(textChanged ( const QString & )), this, SLOT(slotUrlChanged( const QString &)));
+ slotUrlChanged( mIndexUrlRequester->lineEdit()->text() );
+}
+
+void IndexDirDialog::slotUrlChanged( const QString &_url )
+{
+ enableButtonOK( !_url.isEmpty() );
+}
+
+
+void IndexDirDialog::slotOk()
+{
+ Prefs::setIndexDirectory( mIndexUrlRequester->url() );
+ accept();
+}
+
+
+IndexProgressDialog::IndexProgressDialog( QWidget *parent )
+ : KDialog( parent, "IndexProgressDialog", true ),
+ mFinished( true )
+{
+ setCaption( i18n("Build Search Indices") );
+
+ QBoxLayout *topLayout = new QVBoxLayout( this );
+ topLayout->setMargin( marginHint() );
+ topLayout->setSpacing( spacingHint() );
+
+ mLabel = new QLabel( this );
+ mLabel->setAlignment( AlignHCenter );
+ topLayout->addWidget( mLabel );
+
+ mProgressBar = new QProgressBar( this );
+ topLayout->addWidget( mProgressBar );
+
+ mLogLabel = new QLabel( i18n("Index creation log:"), this );
+ topLayout->addWidget( mLogLabel );
+
+ mLogView = new QTextEdit( this );
+ mLogView->setTextFormat( LogText );
+ mLogView->setMinimumHeight( 200 );
+ topLayout->addWidget( mLogView, 1 );
+
+ QBoxLayout *buttonLayout = new QHBoxLayout( topLayout );
+
+ buttonLayout->addStretch( 1 );
+
+ mDetailsButton = new QPushButton( this );
+ connect( mDetailsButton, SIGNAL( clicked() ), SLOT( toggleDetails() ) );
+ buttonLayout->addWidget( mDetailsButton );
+
+ hideDetails();
+
+ mEndButton = new QPushButton( this );
+ connect( mEndButton, SIGNAL( clicked() ), SLOT( slotEnd() ) );
+ buttonLayout->addWidget( mEndButton );
+
+ setFinished( false );
+}
+
+IndexProgressDialog::~IndexProgressDialog()
+{
+ if ( !mLogView->isHidden() ) {
+ KConfig *cfg = KGlobal::config();
+ cfg->setGroup( "indexprogressdialog" );
+ cfg->writeEntry( "size", size() );
+ }
+}
+
+void IndexProgressDialog::setTotalSteps( int steps )
+{
+ mProgressBar->setTotalSteps( steps );
+ mProgressBar->setProgress( 0 );
+ setFinished( false );
+ mLogView->clear();
+}
+
+void IndexProgressDialog::advanceProgress()
+{
+ mProgressBar->setProgress( mProgressBar->progress() + 1 );
+}
+
+void IndexProgressDialog::setLabelText( const QString &text )
+{
+ mLabel->setText( text );
+}
+
+void IndexProgressDialog::setMinimumLabelWidth( int width )
+{
+ mLabel->setMinimumWidth( width );
+}
+
+void IndexProgressDialog::setFinished( bool finished )
+{
+ if ( finished == mFinished ) return;
+
+ mFinished = finished;
+
+ if ( mFinished ) {
+ mEndButton->setText( i18n("Close") );
+ mLabel->setText( i18n("Index creation finished.") );
+ } else {
+ mEndButton->setText( i18n("Stop") );
+ }
+}
+
+void IndexProgressDialog::appendLog( const QString &text )
+{
+ mLogView->append( text );
+}
+
+void IndexProgressDialog::slotEnd()
+{
+ if ( mFinished ) {
+ emit closed();
+ accept();
+ } else {
+ emit cancelled();
+ reject();
+ }
+}
+
+void IndexProgressDialog::toggleDetails()
+{
+ KConfig *cfg = KGlobal::config();
+ cfg->setGroup( "indexprogressdialog" );
+ if ( mLogView->isHidden() ) {
+ mLogLabel->show();
+ mLogView->show();
+ mDetailsButton->setText( i18n("Details <<") );
+ QSize size = cfg->readSizeEntry( "size" );
+ if ( !size.isEmpty() ) resize( size );
+ } else {
+ cfg->writeEntry( "size", size() );
+ hideDetails();
+ }
+}
+
+void IndexProgressDialog::hideDetails()
+{
+ mLogLabel->hide();
+ mLogView->hide();
+ mDetailsButton->setText( i18n("Details >>") );
+ layout()->activate();
+ adjustSize();
+}
+
+
+KCMHelpCenter::KCMHelpCenter( KHC::SearchEngine *engine, QWidget *parent,
+ const char *name)
+ : DCOPObject( "kcmhelpcenter" ),
+ KDialogBase( parent, name, false, i18n("Build Search Index"),
+ Ok | Cancel, Ok, true ),
+ mEngine( engine ), mProgressDialog( 0 ), mCurrentEntry( 0 ), mCmdFile( 0 ),
+ mProcess( 0 ), mIsClosing( false ), mRunAsRoot( false )
+{
+ QWidget *widget = makeMainWidget();
+
+ setupMainWidget( widget );
+
+ setButtonOK( i18n("Build Index") );
+
+ mConfig = KGlobal::config();
+
+ DocMetaInfo::self()->scanMetaInfo();
+
+ load();
+
+ bool success = kapp->dcopClient()->connectDCOPSignal( "khc_indexbuilder",
+ 0, "buildIndexProgress()", "kcmhelpcenter",
+ "slotIndexProgress()", false );
+ if ( !success ) kdError() << "connect DCOP signal failed" << endl;
+
+ success = kapp->dcopClient()->connectDCOPSignal( "khc_indexbuilder",
+ 0, "buildIndexError(QString)", "kcmhelpcenter",
+ "slotIndexError(QString)", false );
+ if ( !success ) kdError() << "connect DCOP signal failed" << endl;
+
+ resize( configDialogSize( "IndexDialog" ) );
+}
+
+KCMHelpCenter::~KCMHelpCenter()
+{
+ saveDialogSize( "IndexDialog" );
+}
+
+void KCMHelpCenter::setupMainWidget( QWidget *parent )
+{
+ QVBoxLayout *topLayout = new QVBoxLayout( parent );
+ topLayout->setSpacing( KDialog::spacingHint() );
+
+ QString helpText =
+ i18n("To be able to search a document, there needs to exist a search\n"
+ "index. The status column of the list below shows, if an index\n"
+ "for a document exists.\n") +
+ i18n("To create an index check the box in the list and press the\n"
+ "\"Build Index\" button.\n");
+
+ QLabel *label = new QLabel( helpText, parent );
+ topLayout->addWidget( label );
+
+ mListView = new KListView( parent );
+ mListView->setFullWidth( true );
+ mListView->addColumn( i18n("Search Scope") );
+ mListView->addColumn( i18n("Status") );
+ mListView->setColumnAlignment( 1, AlignCenter );
+ topLayout->addWidget( mListView );
+ connect( mListView, SIGNAL( clicked( QListViewItem * ) ),
+ SLOT( checkSelection() ) );
+
+ QBoxLayout *urlLayout = new QHBoxLayout( topLayout );
+
+ QLabel *urlLabel = new QLabel( i18n("Index folder:"), parent );
+ urlLayout->addWidget( urlLabel );
+
+ mIndexDirLabel = new QLabel( parent );
+ urlLayout->addWidget( mIndexDirLabel, 1 );
+
+ QPushButton *button = new QPushButton( i18n("Change..."), parent );
+ connect( button, SIGNAL( clicked() ), SLOT( showIndexDirDialog() ) );
+ urlLayout->addWidget( button );
+
+ QBoxLayout *buttonLayout = new QHBoxLayout( topLayout );
+
+ buttonLayout->addStretch( 1 );
+}
+
+void KCMHelpCenter::defaults()
+{
+}
+
+bool KCMHelpCenter::save()
+{
+ kdDebug(1401) << "KCMHelpCenter::save()" << endl;
+
+ if ( !QFile::exists( Prefs::indexDirectory() ) ) {
+ KMessageBox::sorry( this,
+ i18n("<qt>The folder <b>%1</b> does not exist; unable to create index.</qt>")
+ .arg( Prefs::indexDirectory() ) );
+ return false;
+ } else {
+ return buildIndex();
+ }
+
+ return true;
+}
+
+void KCMHelpCenter::load()
+{
+ mIndexDirLabel->setText( Prefs::indexDirectory() );
+
+ mListView->clear();
+
+ DocEntry::List entries = DocMetaInfo::self()->docEntries();
+ DocEntry::List::ConstIterator it;
+ for( it = entries.begin(); it != entries.end(); ++it ) {
+// kdDebug(1401) << "Entry: " << (*it)->name() << " Indexer: '"
+// << (*it)->indexer() << "'" << endl;
+ if ( mEngine->canSearch( *it ) && mEngine->needsIndex( *it ) ) {
+ ScopeItem *item = new ScopeItem( mListView, *it );
+ item->setOn( (*it)->searchEnabled() );
+ }
+ }
+
+ updateStatus();
+}
+
+void KCMHelpCenter::updateStatus()
+{
+ QListViewItemIterator it( mListView );
+ while ( it.current() != 0 ) {
+ ScopeItem *item = static_cast<ScopeItem *>( it.current() );
+ QString status;
+ if ( item->entry()->indexExists( Prefs::indexDirectory() ) ) {
+ status = i18n("OK");
+ item->setOn( false );
+ } else {
+ status = i18n("Missing");
+ }
+ item->setText( 1, status );
+
+ ++it;
+ }
+
+ checkSelection();
+}
+
+bool KCMHelpCenter::buildIndex()
+{
+ kdDebug(1401) << "Build Index" << endl;
+
+ kdDebug() << "IndexPath: '" << Prefs::indexDirectory() << "'" << endl;
+
+ if ( mProcess ) {
+ kdError() << "Error: Index Process still running." << endl;
+ return false;
+ }
+
+ mIndexQueue.clear();
+
+ QFontMetrics fm( font() );
+ int maxWidth = 0;
+
+ mCmdFile = new KTempFile;
+ mCmdFile->setAutoDelete( true );
+ QTextStream *ts = mCmdFile->textStream();
+ if ( !ts ) {
+ kdError() << "Error opening command file." << endl;
+ deleteCmdFile();
+ return false;
+ } else {
+ kdDebug() << "Writing to file '" << mCmdFile->name() << "'" << endl;
+ }
+
+ bool hasError = false;
+
+ QListViewItemIterator it( mListView );
+ while ( it.current() != 0 ) {
+ ScopeItem *item = static_cast<ScopeItem *>( it.current() );
+ if ( item->isOn() ) {
+ DocEntry *entry = item->entry();
+
+ QString docText = i18n("Document '%1' (%2):\n")
+ .arg( entry->identifier() )
+ .arg( entry->name() );
+ if ( entry->documentType().isEmpty() ) {
+ KMessageBox::sorry( this, docText +
+ i18n("No document type.") );
+ hasError = true;
+ } else {
+ SearchHandler *handler = mEngine->handler( entry->documentType() );
+ if ( !handler ) {
+ KMessageBox::sorry( this, docText +
+ i18n("No search handler available for document type '%1'.")
+ .arg( entry->documentType() ) );
+ hasError = true;
+ } else {
+ QString indexer = handler->indexCommand( entry->identifier() );
+ if ( indexer.isEmpty() ) {
+ KMessageBox::sorry( this, docText +
+ i18n("No indexing command specified for document type '%1'.")
+ .arg( entry->documentType() ) );
+ hasError = true;
+ } else {
+ indexer.replace( QRegExp( "%i" ), entry->identifier() );
+ indexer.replace( QRegExp( "%d" ), Prefs::indexDirectory() );
+ indexer.replace( QRegExp( "%p" ), entry->url() );
+ kdDebug() << "INDEXER: " << indexer << endl;
+ *ts << indexer << endl;
+
+ int width = fm.width( entry->name() );
+ if ( width > maxWidth ) maxWidth = width;
+
+ mIndexQueue.append( entry );
+ }
+ }
+ }
+ }
+ ++it;
+ }
+
+ mCmdFile->close();
+
+ if ( mIndexQueue.isEmpty() ) {
+ deleteCmdFile();
+ return !hasError;
+ }
+
+ mCurrentEntry = mIndexQueue.begin();
+ QString name = (*mCurrentEntry)->name();
+
+ if ( !mProgressDialog ) {
+ mProgressDialog = new IndexProgressDialog( this );
+ connect( mProgressDialog, SIGNAL( cancelled() ),
+ SLOT( cancelBuildIndex() ) );
+ connect( mProgressDialog, SIGNAL( closed() ),
+ SLOT( slotProgressClosed() ) );
+ }
+ mProgressDialog->setLabelText( name );
+ mProgressDialog->setTotalSteps( mIndexQueue.count() );
+ mProgressDialog->setMinimumLabelWidth( maxWidth );
+ mProgressDialog->show();
+
+ startIndexProcess();
+
+ return true;
+}
+
+void KCMHelpCenter::startIndexProcess()
+{
+ kdDebug() << "KCMHelpCenter::startIndexProcess()" << endl;
+
+ mProcess = new KProcess;
+
+ if ( mRunAsRoot ) {
+ *mProcess << "kdesu" << "--nonewdcop";
+ kdDebug() << "Run as root" << endl;
+ }
+
+ *mProcess << locate("exe", "khc_indexbuilder");
+ *mProcess << mCmdFile->name();
+ *mProcess << Prefs::indexDirectory();
+
+ connect( mProcess, SIGNAL( processExited( KProcess * ) ),
+ SLOT( slotIndexFinished( KProcess * ) ) );
+ connect( mProcess, SIGNAL( receivedStdout( KProcess *, char *, int ) ),
+ SLOT( slotReceivedStdout(KProcess *, char *, int ) ) );
+ connect( mProcess, SIGNAL( receivedStderr( KProcess *, char *, int ) ),
+ SLOT( slotReceivedStderr( KProcess *, char *, int ) ) );
+
+ if ( !mProcess->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) {
+ kdError() << "KCMHelpcenter::startIndexProcess(): Failed to start process."
+ << endl;
+ }
+}
+
+void KCMHelpCenter::cancelBuildIndex()
+{
+ kdDebug() << "cancelBuildIndex()" << endl;
+
+ deleteProcess();
+ deleteCmdFile();
+ mIndexQueue.clear();
+
+ if ( mIsClosing ) {
+ mIsClosing = false;
+ }
+}
+
+void KCMHelpCenter::slotIndexFinished( KProcess *proc )
+{
+ kdDebug() << "KCMHelpCenter::slotIndexFinished()" << endl;
+
+ if ( proc == 0 ) {
+ kdWarning() << "Process null." << endl;
+ return;
+ }
+
+ if ( proc != mProcess ) {
+ kdError() << "Unexpected Process finished." << endl;
+ return;
+ }
+
+ if ( mProcess->normalExit() && mProcess->exitStatus() == 2 ) {
+ if ( mRunAsRoot ) {
+ kdError() << "Insufficient permissions." << endl;
+ } else {
+ kdDebug() << "Insufficient permissions. Trying again as root." << endl;
+ mRunAsRoot = true;
+ deleteProcess();
+ startIndexProcess();
+ return;
+ }
+ } else if ( !mProcess->normalExit() || mProcess->exitStatus() != 0 ) {
+ kdDebug() << "KProcess reported an error." << endl;
+ KMessageBox::error( this, i18n("Failed to build index.") );
+ } else {
+ mConfig->setGroup( "Search" );
+ mConfig->writeEntry( "IndexExists", true );
+ emit searchIndexUpdated();
+ }
+
+ deleteProcess();
+ deleteCmdFile();
+
+ mCurrentEntry = 0;
+
+ if ( mProgressDialog ) {
+ mProgressDialog->setFinished( true );
+ }
+
+ mStdOut = QString();
+ mStdErr = QString();
+
+ if ( mIsClosing ) {
+ if ( !mProgressDialog->isVisible() ) {
+ mIsClosing = false;
+ accept();
+ }
+ }
+}
+
+void KCMHelpCenter::deleteProcess()
+{
+ delete mProcess;
+ mProcess = 0;
+}
+
+void KCMHelpCenter::deleteCmdFile()
+{
+ delete mCmdFile;
+ mCmdFile = 0;
+}
+
+void KCMHelpCenter::slotIndexProgress()
+{
+ if( !mProcess )
+ return;
+
+ kdDebug() << "KCMHelpCenter::slotIndexProgress()" << endl;
+
+ updateStatus();
+
+ advanceProgress();
+}
+
+void KCMHelpCenter::slotIndexError( const QString &str )
+{
+ if( !mProcess )
+ return;
+
+ kdDebug() << "KCMHelpCenter::slotIndexError()" << endl;
+
+ KMessageBox::sorry( this, i18n("Error executing indexing build command:\n%1")
+ .arg( str ) );
+
+ if ( mProgressDialog ) {
+ mProgressDialog->appendLog( "<i>" + str + "</i>" );
+ }
+
+ advanceProgress();
+}
+
+void KCMHelpCenter::advanceProgress()
+{
+ if ( mProgressDialog && mProgressDialog->isVisible() ) {
+ mProgressDialog->advanceProgress();
+ mCurrentEntry++;
+ if ( mCurrentEntry != mIndexQueue.end() ) {
+ QString name = (*mCurrentEntry)->name();
+ mProgressDialog->setLabelText( name );
+ }
+ }
+}
+
+void KCMHelpCenter::slotReceivedStdout( KProcess *, char *buffer, int buflen )
+{
+ QString text = QString::fromLocal8Bit( buffer, buflen );
+ int pos = text.findRev( '\n' );
+ if ( pos < 0 ) {
+ mStdOut.append( text );
+ } else {
+ if ( mProgressDialog ) {
+ mProgressDialog->appendLog( mStdOut + text.left( pos ) );
+ mStdOut = text.mid( pos + 1 );
+ }
+ }
+}
+
+void KCMHelpCenter::slotReceivedStderr( KProcess *, char *buffer, int buflen )
+{
+ QString text = QString::fromLocal8Bit( buffer, buflen );
+ int pos = text.findRev( '\n' );
+ if ( pos < 0 ) {
+ mStdErr.append( text );
+ } else {
+ if ( mProgressDialog ) {
+ mProgressDialog->appendLog( "<i>" + mStdErr + text.left( pos ) +
+ "</i>");
+ mStdErr = text.mid( pos + 1 );
+ }
+ }
+}
+
+void KCMHelpCenter::slotOk()
+{
+ if ( buildIndex() ) {
+ if ( !mProcess ) accept();
+ else mIsClosing = true;
+ }
+}
+
+void KCMHelpCenter::slotProgressClosed()
+{
+ kdDebug() << "KCMHelpCenter::slotProgressClosed()" << endl;
+
+ if ( mIsClosing ) accept();
+}
+
+void KCMHelpCenter::showIndexDirDialog()
+{
+ IndexDirDialog dlg( this );
+ if ( dlg.exec() == QDialog::Accepted ) {
+ load();
+ }
+}
+
+void KCMHelpCenter::checkSelection()
+{
+ int count = 0;
+
+ QListViewItemIterator it( mListView );
+ while ( it.current() != 0 ) {
+ ScopeItem *item = static_cast<ScopeItem *>( it.current() );
+ if ( item->isOn() ) {
+ ++count;
+ }
+ ++it;
+ }
+
+ enableButtonOK( count != 0 );
+}
+
+#include "kcmhelpcenter.moc"
+
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/kcmhelpcenter.desktop b/khelpcenter/kcmhelpcenter.desktop
new file mode 100644
index 00000000..54ae1c7e
--- /dev/null
+++ b/khelpcenter/kcmhelpcenter.desktop
@@ -0,0 +1,236 @@
+[Desktop Entry]
+Type=Application
+Exec=kcmshell kcmhelpcenter
+Icon=help
+
+X-KDE-SubstituteUID=true
+X-KDE-ModuleType=Library
+X-KDE-Library=helpcenter
+X-KDE-RootOnly=true
+X-KDE-HasReadOnlyMode=true
+X-KDE-ParentApp=kcontrol
+
+Name=Help Index
+Name[af]=Hulp Indeks
+Name[ar]=فهرس المساعدة
+Name[be]=Індэкс дапамогі
+Name[bg]=Помощна информация
+Name[bn]=সাহায্য সূচি
+Name[br]=Meneger ar skoazell
+Name[bs]=Indeks pomoći
+Name[ca]=Índex d'ajuda
+Name[cs]=Rejstřík nápovědy
+Name[csb]=Indeks pòmòcë
+Name[cy]=Mynegai Cymorth
+Name[da]=Hjælpeindeks
+Name[de]=Hilfeindex
+Name[el]=Ευρετήριο βοήθειας
+Name[eo]=Helpindekso
+Name[es]=Índice de ayuda
+Name[et]=Abifailide indeks
+Name[eu]=Laguntza indizea
+Name[fa]=نمایۀ کمک
+Name[fi]=Ohjeen hakemisto
+Name[fr]=Index d'aide
+Name[fy]=Help-yndeks
+Name[ga]=Innéacs na Cabhrach
+Name[gl]=Índice de Axuda
+Name[he]=אינדקס עזרה
+Name[hi]=मदद सूची
+Name[hr]=Indeks pomoći
+Name[hu]=Dokumentációkeresési index
+Name[is]=Hjálparyfirlit
+Name[it]=Indice della guida
+Name[ja]=ヘルプインデックス
+Name[ka]=დახმარების ინდექსი
+Name[kk]=Анықтама индексі
+Name[km]=លិបិក្រម​ជំនួយ
+Name[ko]=도움말 찾아보기
+Name[lo]=ດັດສະນີ
+Name[lt]=Pagalbos rodyklė
+Name[lv]=Palīdzības indekss
+Name[mk]=Индекс за помош
+Name[mn]=Тусламж товчоо
+Name[ms]=Indeks Bantuan
+Name[mt]=Indiċi tal-għajnuna
+Name[nb]=Hjelpindeks
+Name[nds]=Hülpindex
+Name[ne]=मद्दत अनुक्रमणिका
+Name[nl]=Documentatie-index
+Name[nn]=Hjelpindeks
+Name[nso]=Palo ya Thuso
+Name[pa]=ਸਹਾਇਤਾ ਤਤਕਰਾ
+Name[pl]=Indeks pomocy
+Name[pt]=Índice da Ajuda
+Name[pt_BR]=Índice de Ajuda
+Name[ro]=Index ajutor
+Name[ru]=Индекс справки
+Name[rw]=Umubarendanga w'Ifashayobora
+Name[se]=Veahkkeindeaksa
+Name[sk]=Index pomocníka
+Name[sl]=Seznam pomoči
+Name[sr]=Индекс помоћи
+Name[sr@Latn]=Indeks pomoći
+Name[sv]=Hjälpindex
+Name[ta]=உதவி பொருளடக்கம்
+Name[te]=సహాయ సూచిక
+Name[tg]=Феҳрасти роҳнамо
+Name[th]=ดัชนีความช่วยเหลือ
+Name[tr]=Yardım İçeriği
+Name[tt]=Yärdäm İsemlege
+Name[uk]=Індекс довідки
+Name[uz]=Yordam indeksi
+Name[uz@cyrillic]=Ёрдам индекси
+Name[ven]=Thusani Index
+Name[vi]=Danh mục Trợ giúp
+Name[wa]=Indecse di l' aidance
+Name[xh]=Uncedo Lwesalathisi
+Name[zh_CN]=帮助索引
+Name[zh_TW]=說明索引
+Name[zu]=Uhlelo lokuqukethwe losizo
+
+Comment=Help center search index configuration and generation
+Comment[af]=Hulp sentrum soektog indeks opstelling en genereering
+Comment[ar]=توليد و تهيئة فهرس البحث لمركز المساعدة
+Comment[be]=Настаўленне і стварэнне індэксу для пошуку ў дакументацыі
+Comment[bg]=Създаване на индекс за ускоряване на търсенето в помощната информация
+Comment[bn]=সহায়িকাসন্ধানসূচি কনফিগারেশন এবং সৃষ্টি
+Comment[bs]=Podešavanje i pravljenje indeksa za pretragu centra za pomoć
+Comment[ca]=Configuració i generació de l'índex de recerca per al Centre d'ajuda
+Comment[cs]=Generování a konfigurace rejstříku nápovědy
+Comment[csb]=Kònfigùracëjë ë generowanié indeksu pòmòcë
+Comment[cy]=Ffurfweddu a chynhyrchu mynegai chwilio y Ganolfan Cymorth
+Comment[da]=Hjælpecenterets indstilling og generering af søgeindeks
+Comment[de]=Stichwortverzeichnis für das Hilfezentrum einrichten und erstellen
+Comment[el]=Ρύθμιση και δημιουργία του ευρετηρίου αναζήτησης του Κέντρου βοήθειας
+Comment[en_GB]=Help centre search index configuration and generation
+Comment[eo]=Agordo kaj fabriko de KHelpcentra serĉindekso
+Comment[es]=Configuración y generación del índice de búsqueda del centro de ayuda
+Comment[et]=Abifailide otsingu indeksi loomine ja seadistamine
+Comment[eu]=Laguntza guneko bilaketa indizearen konfigurazio eta sorkuntza
+Comment[fa]=تولید و پیکربندی نمایۀ جستجوی مرکز کمک
+Comment[fi]=Ohjeen hakuindeksin asetukset ja luonti
+Comment[fr]=Configuration et génération de l'index de recherche du centre d'aide
+Comment[fy]=Sykjeyndeks fan it helpsintrum ynstellen en generearen
+Comment[gl]=Configuración e xeración do índice de procura do centro de axuda
+Comment[he]=שינוי הגדרות ויצירת אינדקס החיפוש של מרכז העזרה
+Comment[hi]=मदद केंद्र खोज तालिका कॉन्फ़िगरेशन तथा ज़ेनरेशन
+Comment[hr]=Konfiguriranje i generiranje indeksa za pretraživanje pomoći
+Comment[hu]=A dokumentáció keresési indexének beállításai
+Comment[is]=Uppsettning og sköpun af leitaryfirliti fyrir hjálparmiðstöðina
+Comment[it]=Configurazione e generazione dell'indice di ricerca della guida.
+Comment[ja]=ヘルプセンターの検索インデックスの設定と生成
+Comment[ka]=KDE-ს დახმარების სისტემაში ინდექსების კონფიგურაცია
+Comment[kk]=Анықтамадан табу индексін баптау
+Comment[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ និង​ការ​បង្កើត​លិបិក្រម​ស្វែងរក សម្រាប់​មជ្ឈមណ្ឌល​ជំនួយ
+Comment[ko]=도움말 찾아보기 설정 및 생성
+Comment[lt]=Pagalbos centro indekso konfigūravimas ir generavimas
+Comment[lv]=Palīdzības centra meklēšanas indeksa konfigurācija un ģenerācija
+Comment[mk]=Конфигурирање и генерирање на индексот на Центарот за Помош
+Comment[mn]=Товчоон тохируулах
+Comment[mt]=Konfigurazzjoni u ġenerazzjoni tal-indiċi ta' tfittxija taċ-ċentru ta' għajnuna
+Comment[nb]=Tilpass søkeindeksen og legg den til i hjelpesenteret
+Comment[nds]=Söökindex för't Hülpzentrum inrichten un maken laten
+Comment[ne]=मद्दत केन्द्र खोजी अनुक्रमणिका कन्फिगरेसन र उत्पादन
+Comment[nl]=Zoekindex van het documentatiecentrum instellen en genereren
+Comment[nn]=Oppsett og generering av søkjeindeks for hjelpesenteret
+Comment[nso]=Thlagiso le peakanyo ya palo ya bangwadi le ya nyako ya bogare bja thuso
+Comment[pa]=ਸਹਾਇਤਾ ਕੇਂਦਰ ਖੋਜ ਤਤਕਰਾ ਸੰਰਚਨਾ ਅਤੇ ਨਿਰਮਾਣ
+Comment[pl]=Konfiguracja i generowanie indeksu pomocy
+Comment[pt]=Configuração e geração do índice de pesquisa do centro de ajuda
+Comment[pt_BR]=Configuração e geração do índice de busca do centro de ajuda
+Comment[ro]=Generează și configurează indexul de căutare pentru Centrul de Ajutor
+Comment[ru]=Настройка индексов справочной системы KDE
+Comment[rw]=Iboneza n'irema umubarendanga w'ishakisha ifashayobora hagati
+Comment[se]=Veahkkeguovddáža ohcanindeavssa heiveheapmi ja ráhkadeapmi
+Comment[sk]=Nastavenie a generovanie indexu pre pomocníka
+Comment[sl]=Nastavitve in ustvarjanje iskalnega indeksa za Središče za pomoč
+Comment[sr]=Подешавање и генерисање индекса за претрагу Центра за помоћ
+Comment[sr@Latn]=Podešavanje i generisanje indeksa za pretragu Centra za pomoć
+Comment[sv]=Skapa och ställ in sökindex för Hjälpcentralen
+Comment[ta]=உதவி மையத்தை தேடும் பொருளடக்கம் வடிவமைத்தல் மற்றும் உருவாக்கல்
+Comment[te]=సహాయ కేంద్ర అన్వెషణ సూచి అమరిక మరయూ తయారుచెయుట
+Comment[tg]=Танзим ва эҷоди феҳристи ҷустуҷӯи роҳнамо
+Comment[th]=การปรับแต่งและสร้างดัชนีสำหรับค้นหาของศูนย์ช่วยเหลือ
+Comment[tr]=Yardım merkezi indeks yapılandırması
+Comment[tt]=Yärdäm üzägeneñ ezläw isemleklären caylaw/ürçetü
+Comment[uk]=Створення та налаштування індексу пошуку центру довідки
+Comment[uz]=Yordam markazining qidiruv indeksini yaratish va moslash
+Comment[uz@cyrillic]=Ёрдам марказининг қидирув индексини яратиш ва мослаш
+Comment[ven]=Nzudzanyo ya index yau setsha senthara ya thuso na murafho
+Comment[vi]=Cấu hình và tạo danh mục tìm kiếm của trung tâm trợ giúp
+Comment[wa]=Apontiaedje et ahivaedje di l' indecse di cweraedje do cinte d' aidance
+Comment[xh]=Uqwalaselo lophendlo loncedo osembindi nolwenziwo
+Comment[zh_CN]=帮助中心搜索索引配置和生成
+Comment[zh_TW]=求助中心搜尋索引的組態與產生
+Comment[zu]=ukuhlanganiselwa kanye nokugaywa kohlelo lokuqukethwe lokusesha indawo yosizo
+
+Keywords=khelpcenter,help,index,search
+Keywords[ar]=khelpcenter,help,index,search,مساعدة,فهرس,بحث
+Keywords[be]=Цэнтр дапамогі,Дапамога,Даведка,Індэкс,Пошук,khelpcenter,help,index,search
+Keywords[bg]=индекс, търсене, помощ, информация, khelpcenter, help, index, search
+Keywords[br]=khelpcenter,skoazell,meneger,klask
+Keywords[bs]=khelpcenter,help,index,search,pretraga,indeks
+Keywords[ca]=khelpcenter,ajuda,índex,cerca
+Keywords[cs]=khelpcenter,nápověda,rejstřík,index,hledání
+Keywords[csb]=centróm pòmòcë,pòmòc,indeks,szëkba
+Keywords[cy]=khelpcenter,kcanolfancymorth,cymorth,mynegai,chwilio
+Keywords[da]=khelpcenter,hjælp,indeks,søg
+Keywords[de]=Hilfezentrum,Index,Stichwortverzeichnis,Suche
+Keywords[el]=khelpcenter,βοήθεια,ευρετήριο,αναζήτηση
+Keywords[eo]=KHelpcentro,helpo,indekso,serĉo,serĉi
+Keywords[es]=khelpcenter,ayuda,índice,búsqueda
+Keywords[et]=abifailid,indeks,otsing
+Keywords[eu]=khelpcenter,laguntza,indizea,bilaketa
+Keywords[fa]=khelpcenter، کمک، نمایه، جستجو
+Keywords[fi]=khelpcenter,ohje,indeksi,haku
+Keywords[fr]=khelpcenter,aide,index,recherche
+Keywords[fy]=khelpcenter,help,index,yndeks,sykje,fine,search,hulp,zoeken
+Keywords[ga]=khelpcenter,cabhair,innéacs,cuardach
+Keywords[gl]=khelpcenter,axuda,índice,procura
+Keywords[he]=khelpcenter,עזרה,אינדקס,חיפוש,help,index,search
+Keywords[hi]=के-हेल्पसेंटर,मदद,तालिका,खोज
+Keywords[hr]=khelpcenter,help,index,search,pomoć,indeks,pretraživanje
+Keywords[hu]=khelpcenter,segítség,index,keresés
+Keywords[is]=khelpcenter,hjálparmiðstöð,hjálp,index,yfirlit,leit
+Keywords[it]=khelpcenter,guida,indice,ricerca
+Keywords[ja]=khelpcenter,ヘルプ,インデックス,検索
+Keywords[km]=khelpcenter,ជំនួយ,លិបិក្រម,ស្វែងរក
+Keywords[lt]=khelpcenter,help,index,search, pagalbos centras, pagalba, indeksas, paieška
+Keywords[lv]=kpalīdzības centrs,palīdzība,indekss,meklēt
+Keywords[mk]=khelpcenter,help,index,search,помош,индекс,пребарувај
+Keywords[mn]=Тусламжийн төв,Товчоо,Товчоон,Хайх
+Keywords[mt]=khelpcenter,help,index,search,għajnuna,indiċi,fittex
+Keywords[nb]=khelpcenter,help,index,search, hjelpesenter,hjelp,indeks,søk
+Keywords[nds]=khelpcenter,Help,Hülp,Hölp,Index,Söken
+Keywords[ne]=केडीई मद्दत केन्द्र, मद्दत, अनुक्रमणिका, खोजी
+Keywords[nl]=khelpcenter,help,index,search,hulp,zoeken,documentatie,handboek
+Keywords[nn]=KHelpCenter,hjelp,indeks,søk
+Keywords[nso]=kbogare bja thuso,thuso,palo ya bangwadi,nyako
+Keywords[pa]=ਸਹਾਇਤਾ ਕੇਂਦਰ,ਸਹਾਇਤਾ,ਤਤਕਰਾ,ਖੋਜ
+Keywords[pl]=centrum pomocy,pomoc,indeks,szukanie
+Keywords[pt]=khelpcenter,ajuda,índice,procura
+Keywords[pt_BR]=centro de ajuda,ajuda,índice,busca
+Keywords[ro]=centrul de ajutor,khelpcenter,ajutor,index,căutare
+Keywords[rw]=k-ifashayoborahagati,ifashayobora,umubarendanga,ishakisha
+Keywords[se]=KHelpCenter,veahkki,indeaksa,indeksa,ohcan
+Keywords[sk]=khelpcenter,help,index,pomocník,hľadanie
+Keywords[sl]=khelpcenter,pomoč,indeks,iskanje
+Keywords[sr]=khelpcenter,помоћ,садржај,претрага
+Keywords[sr@Latn]=khelpcenter,pomoć,sadržaj,pretraga
+Keywords[sv]=khelpcenter,hjälp,index,sök
+Keywords[ta]=kஉதவி மையம், உதவி, சுட்டு இணைப்பு முறை, தேடுதல், தேடு
+Keywords[te]=కెసహాయకేంద్రం,సహాయం,సూచిక, అన్వెషణ
+Keywords[th]=ศูนย์ช่วยเหลือ,ช่วยเหลือ,ดัชนี,ค้นหา
+Keywords[tr]=khelpcenter,yardım,ara,tarama,indeks
+Keywords[uk]=khelpcenter,довідка,індекс,пошук
+Keywords[uz]=khelpcenter,yordam,indeks,qidirish
+Keywords[uz@cyrillic]=khelpcenter,ёрдам,индекс,қидириш
+Keywords[ven]=senthara ya thuso k,thuso,index,toda
+Keywords[vi]=trung tâm trợ giúp KDE,trợ giúp,danh mục,tìm kiếm
+Keywords[wa]=khelpcenter,aide,aidance,indecse,trover,cwerî
+Keywords[xh]=khelpcenter,uncedo,isalathisi,uphendlo
+Keywords[zh_CN]=khelpcenter,help,index,search,帮助中心,帮助,索引,搜索
+Keywords[zh_TW]=khelpcenter,help,index,search,求助,索引,搜尋
+Keywords[zu]=khelpcenter,usizo,uhlelo lokuqukethwe,usesho
+Categories=Qt;KDE;X-KDE-settings-system;
diff --git a/khelpcenter/kcmhelpcenter.h b/khelpcenter/kcmhelpcenter.h
new file mode 100644
index 00000000..8a7b1f4c
--- /dev/null
+++ b/khelpcenter/kcmhelpcenter.h
@@ -0,0 +1,180 @@
+/*
+ This file is part of KHelpcenter.
+
+ Copyright (C) 2002 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This program 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef KCMHELPCENTER_H
+#define KCMHELPCENTER_H
+
+#include <kdialog.h>
+#include <kdialogbase.h>
+
+#include <dcopobject.h>
+
+#include "scopeitem.h"
+
+class QPushButton;
+class QProgressBar;
+class QTextEdit;
+class QLabel;
+
+class KProcess;
+class KConfig;
+class KAboutData;
+class KTempFile;
+class KURLRequester;
+class KListView;
+
+namespace KHC {
+class HtmlSearchConfig;
+class DocEntry;
+class SearchEngine;
+}
+
+class IndexDirDialog : public KDialogBase
+{
+ Q_OBJECT
+ public:
+ IndexDirDialog( QWidget *parent );
+
+ protected slots:
+ void slotOk();
+ void slotUrlChanged( const QString &_url);
+ private:
+ KURLRequester *mIndexUrlRequester;
+};
+
+class IndexProgressDialog : public KDialog
+{
+ Q_OBJECT
+ public:
+ IndexProgressDialog( QWidget *parent );
+ ~IndexProgressDialog();
+
+ void setTotalSteps( int );
+ void advanceProgress();
+ void setLabelText( const QString & );
+ void setMinimumLabelWidth( int width );
+ void setFinished( bool );
+
+ void appendLog( const QString &text );
+
+ signals:
+ void closed();
+ void cancelled();
+
+ protected:
+ void hideDetails();
+
+ protected slots:
+ void slotEnd();
+ void toggleDetails();
+
+ private:
+ QLabel *mLabel;
+ QProgressBar *mProgressBar;
+ QLabel *mLogLabel;
+ QTextEdit *mLogView;
+ QPushButton *mDetailsButton;
+ QPushButton *mEndButton;
+
+ bool mFinished;
+};
+
+class KCMHelpCenterIface : virtual public DCOPObject
+{
+ K_DCOP
+ k_dcop:
+ virtual void slotIndexProgress() = 0;
+ virtual void slotIndexError( const QString & ) = 0;
+};
+
+class KCMHelpCenter : public KDialogBase, virtual public KCMHelpCenterIface
+{
+ Q_OBJECT
+ public:
+ KCMHelpCenter( KHC::SearchEngine *, QWidget *parent = 0,
+ const char *name = 0 );
+ ~KCMHelpCenter();
+
+ void load();
+ bool save();
+ void defaults();
+
+ public slots:
+
+ signals:
+ void searchIndexUpdated();
+
+ protected slots:
+ bool buildIndex();
+ void cancelBuildIndex();
+ void slotIndexFinished( KProcess * );
+ void slotIndexProgress();
+ void slotIndexError( const QString & );
+ void slotReceivedStdout(KProcess *proc, char *buffer, int buflen);
+ void slotReceivedStderr(KProcess *proc, char *buffer, int buflen);
+ void slotProgressClosed();
+
+ void slotOk();
+
+ void showIndexDirDialog();
+
+ void checkSelection();
+
+ protected:
+ void setupMainWidget( QWidget *parent );
+ void updateStatus();
+ void startIndexProcess();
+
+ void deleteProcess();
+ void deleteCmdFile();
+
+ void advanceProgress();
+
+ private:
+ KHC::SearchEngine *mEngine;
+
+ KListView *mListView;
+ QLabel *mIndexDirLabel;
+ QPushButton *mBuildButton;
+ IndexProgressDialog *mProgressDialog;
+
+ QValueList<KHC::DocEntry *> mIndexQueue;
+ QValueList<KHC::DocEntry *>::ConstIterator mCurrentEntry;
+
+ KConfig *mConfig;
+
+ KAboutData *mAboutData;
+
+ KHC::HtmlSearchConfig *mHtmlSearchTab;
+ QWidget *mScopeTab;
+
+ KTempFile *mCmdFile;
+
+ KProcess *mProcess;
+
+ bool mIsClosing;
+
+ QString mStdOut;
+ QString mStdErr;
+
+ bool mRunAsRoot;
+};
+
+#endif
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/khc_indexbuilder.cpp b/khelpcenter/khc_indexbuilder.cpp
new file mode 100644
index 00000000..ef7c239c
--- /dev/null
+++ b/khelpcenter/khc_indexbuilder.cpp
@@ -0,0 +1,221 @@
+/*
+ This file is part of the KDE Help Center
+
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301, USA
+*/
+
+#include "khc_indexbuilder.h"
+
+#include "version.h"
+
+#include <kaboutdata.h>
+#include <klocale.h>
+#include <kcmdlineargs.h>
+#include <kuniqueapplication.h>
+#include <kdebug.h>
+#include <dcopclient.h>
+#include <kprocess.h>
+#include <kstandarddirs.h>
+#include <kconfig.h>
+
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qdir.h>
+#include <qtextstream.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <iostream>
+
+using namespace KHC;
+
+IndexBuilder::IndexBuilder(const QString& cmdFile)
+{
+ m_cmdFile = cmdFile;
+ kdDebug(1402) << "IndexBuilder()" << endl;
+}
+
+void IndexBuilder::buildIndices()
+{
+ QFile f( m_cmdFile );
+ if ( !f.open( IO_ReadOnly ) ) {
+ kdError() << "Unable to open file '" << m_cmdFile << "'" << endl;
+ exit( 1 );
+ }
+ kdDebug(1402) << "Opened file '" << m_cmdFile << "'" << endl;
+ QTextStream ts( &f );
+ QString line = ts.readLine();
+ while ( !line.isNull() ) {
+ kdDebug(1402) << "LINE: " << line << endl;
+ mCmdQueue.append( line );
+ line = ts.readLine();
+ }
+
+ processCmdQueue();
+}
+
+void IndexBuilder::processCmdQueue()
+{
+ kdDebug(1402) << "IndexBuilder::processCmdQueue()" << endl;
+
+ QStringList::Iterator it = mCmdQueue.begin();
+
+ if ( it == mCmdQueue.end() ) {
+ quit();
+ return;
+ }
+
+ QString cmd = *it;
+
+ kdDebug(1402) << "PROCESS: " << cmd << endl;
+
+ KProcess *proc = new KProcess;
+ proc->setRunPrivileged( true );
+
+ QStringList args = QStringList::split( " ", cmd );
+ *proc << args;
+
+
+ connect( proc, SIGNAL( processExited( KProcess * ) ),
+ SLOT( slotProcessExited( KProcess * ) ) );
+ connect( proc, SIGNAL( receivedStdout(KProcess *, char *, int ) ),
+ SLOT( slotReceivedStdout(KProcess *, char *, int ) ) );
+ connect( proc, SIGNAL( receivedStderr(KProcess *, char *, int ) ),
+ SLOT( slotReceivedStderr(KProcess *, char *, int ) ) );
+
+ mCmdQueue.remove( it );
+
+ if ( !proc->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) {
+ sendErrorSignal( i18n("Unable to start command '%1'.").arg( cmd ) );
+ processCmdQueue();
+ }
+}
+
+void IndexBuilder::slotProcessExited( KProcess *proc )
+{
+ kdDebug(1402) << "IndexBuilder::slotIndexFinished()" << endl;
+
+ if ( !proc->normalExit() ) {
+ kdError(1402) << "Process failed" << endl;
+ } else {
+ int status = proc->exitStatus();
+ kdDebug(1402) << "Exit status: " << status << endl;
+ }
+
+ delete proc;
+
+ sendProgressSignal();
+
+ processCmdQueue();
+}
+
+void IndexBuilder::slotReceivedStdout( KProcess *, char *buffer, int buflen )
+{
+ QString text = QString::fromLocal8Bit( buffer, buflen );
+ std::cout << text.local8Bit().data() << std::flush;
+}
+
+void IndexBuilder::slotReceivedStderr( KProcess *, char *buffer, int buflen )
+{
+ QString text = QString::fromLocal8Bit( buffer, buflen );
+ std::cerr << text.local8Bit().data() << std::flush;
+}
+
+void IndexBuilder::sendErrorSignal( const QString &error )
+{
+ kdDebug(1402) << "IndexBuilder::sendErrorSignal()" << endl;
+
+ QByteArray params;
+ QDataStream stream( params, IO_WriteOnly );
+ stream << error;
+ kapp->dcopClient()->emitDCOPSignal("buildIndexError(QString)", params );
+}
+
+void IndexBuilder::sendProgressSignal()
+{
+ kdDebug(1402) << "IndexBuilder::sendProgressSignal()" << endl;
+
+ kapp->dcopClient()->emitDCOPSignal("buildIndexProgress()", QByteArray() );
+}
+
+void IndexBuilder::quit()
+{
+ kdDebug(1402) << "IndexBuilder::quit()" << endl;
+
+ kapp->quit();
+}
+
+
+static KCmdLineOptions options[] =
+{
+ { "+cmdfile", I18N_NOOP("Document to be indexed"), 0 },
+ { "+indexdir", I18N_NOOP("Index directory"), 0 },
+ KCmdLineLastOption
+};
+
+int main( int argc, char **argv )
+{
+ KAboutData aboutData( "khc_indexbuilder",
+ I18N_NOOP("KHelpCenter Index Builder"),
+ HELPCENTER_VERSION,
+ I18N_NOOP("The KDE Help Center"),
+ KAboutData::License_GPL,
+ I18N_NOOP("(c) 2003, The KHelpCenter developers") );
+
+ aboutData.addAuthor( "Cornelius Schumacher", 0, "schumacher@kde.org" );
+
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ KCmdLineArgs::addCmdLineOptions( options );
+ KUniqueApplication::addCmdLineOptions();
+
+ KApplication app;
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ if ( args->count() != 2 ) {
+ kdDebug(1402) << "Wrong number of arguments." << endl;
+ return 1;
+ }
+
+ QString cmdFile = args->arg( 0 );
+ QString indexDir = args->arg( 1 );
+
+ kdDebug(1402) << "cmdFile: " << cmdFile << endl;
+ kdDebug(1402) << "indexDir: " << indexDir << endl;
+
+ QFile file( indexDir + "/testaccess" );
+ if ( !file.open( IO_WriteOnly ) || file.putch( ' ' ) < 0 ) {
+ kdDebug(1402) << "access denied" << endl;
+ return 2;
+ } else {
+ kdDebug(1402) << "can access" << endl;
+ file.remove();
+ }
+
+ app.dcopClient()->registerAs( "khc_indexbuilder", false );
+
+ IndexBuilder builder(cmdFile);
+
+ QTimer::singleShot(0, &builder, SLOT(buildIndices()));
+
+ return app.exec();
+}
+
+#include "khc_indexbuilder.moc"
+
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/khc_indexbuilder.h b/khelpcenter/khc_indexbuilder.h
new file mode 100644
index 00000000..4bd5415a
--- /dev/null
+++ b/khelpcenter/khc_indexbuilder.h
@@ -0,0 +1,61 @@
+/*
+ * This file is part of the KDE Help Center
+ *
+ * Copyright (C) 2003 Cornelius Schumacher <schumacher@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef KHC_INDEXBUILDER_H
+#define KHC_INDEXBUILDER_H
+
+#include <kuniqueapplication.h>
+
+#include <qobject.h>
+#include <qtimer.h>
+
+class KProcess;
+
+namespace KHC {
+
+class IndexBuilder : public QObject
+{
+ Q_OBJECT
+ public:
+ IndexBuilder(const QString& cmdFile);
+
+ void sendProgressSignal();
+ void sendErrorSignal( const QString &error );
+ void quit();
+
+ void processCmdQueue();
+
+ protected slots:
+ void buildIndices();
+ void slotProcessExited( KProcess * );
+ void slotReceivedStdout( KProcess *, char *buffer, int buflen );
+ void slotReceivedStderr( KProcess *, char *buffer, int buflen );
+
+ private:
+ QString m_cmdFile;
+ QTimer mTimer;
+ QStringList mCmdQueue;
+};
+
+}
+
+#endif
+
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/khelpcenter.desktop b/khelpcenter/khelpcenter.desktop
new file mode 100644
index 00000000..cf3f6a70
--- /dev/null
+++ b/khelpcenter/khelpcenter.desktop
@@ -0,0 +1,133 @@
+[Desktop Entry]
+Name=KHelpCenter
+Name[af]=Khulpsentrum
+Name[be]=Цэнтр дапамогі KDE
+Name[bg]=Помощен център
+Name[cs]=Centrum nápovědy
+Name[csb]=Centróm Pòmòcë
+Name[cy]=KCanolfanCymorth
+Name[da]=KHjælpecenter
+Name[de]=KDE-Hilfezentrum
+Name[en_GB]=KHelpCentre
+Name[eo]=KHelpCentro
+Name[es]=KHelpcenter
+Name[et]=KDE abikeskus
+Name[fr]=Centre d'aide de KDE
+Name[gl]=Centro de Axuda de KDE
+Name[hi]=के-हेल्प-सेंटर
+Name[is]=Hjálparkerfi KDE
+Name[ja]=K ヘルプセンター
+Name[lo]=ສູນຊ່ວຍເຫລືອ - K
+Name[lv]=KPalīdzībasCentrs
+Name[mn]=КДЭ-Тусламжийн төв
+Name[nds]=KDE-Hülpzentrum
+Name[ne]=केडीई मद्दत केन्द्र
+Name[nso]=KBogare bja Thuso
+Name[pa]=ਕੇਸਹਾਇਤਾਕੇਂਦਰ
+Name[pl]=Centrum Pomocy
+Name[pt_BR]=Centro de Ajuda
+Name[ro]=Centrul de ajutor KDE
+Name[ru]=Центр справки
+Name[rw]=K-UmwanyaGufasha
+Name[sv]=Hjälpcentralen
+Name[ta]=Kஉதவிமையம்
+Name[te]=కెసహాయ కేంద్రం
+Name[tg]=Маркази роҳнамо
+Name[th]=ศูนย์ช่วยเหลือ K
+Name[tr]=KDE Yardım Merkezi
+Name[uz]=Yordam markazi
+Name[uz@cyrillic]=Ёрдам маркази
+Name[ven]=Senthara ya thuso ya K
+Name[vi]=Trung tâm Trợ giúp KDE
+Name[wa]=KCinteDAidance
+Name[zh_CN]=KHelpcenter
+Comment=The KDE Help Center
+Comment[af]=Die Kde Hulp Sentrum
+Comment[ar]=مركز KDE للمساعدة
+Comment[az]=KDE Yardım Mərkəzi
+Comment[be]=Цэнтр дапамогі KDE
+Comment[bg]=Център за помощна информация
+Comment[bn]=কে.ডি.ই. সাহায্য কেন্দ্র
+Comment[br]=Kreizenn sikour KDE
+Comment[bs]=KDE centar za pomoć
+Comment[ca]=El centre d'ajuda KDE
+Comment[cs]=Centrum nápovědy prostředí KDE
+Comment[csb]=Centróm Pòmòcë KDE
+Comment[cy]=Canolfan Cymorth KDE
+Comment[da]=KDE's hjælpecenter
+Comment[de]=Das KDE-Hilfezentrum
+Comment[el]=Το κέντρο βοήθειας του KDE
+Comment[en_GB]=The KDE Help Centre
+Comment[eo]=La KDE-helpocentro
+Comment[es]=El centro de ayuda de KDE
+Comment[et]=KDE abikeskus
+Comment[eu]=KDE laguntza gunea
+Comment[fa]=مرکز کمک KDE
+Comment[fi]=KDE:n Ohje
+Comment[fr]=Le centre de documentation de KDE
+Comment[fy]=It KDE-dokumintaasjesintrum
+Comment[ga]=Lárionad Cabhrach KDE
+Comment[gl]=O Centro de Axuda de KDE
+Comment[he]=מרכז העזרה של KDE
+Comment[hi]=केडीई मदद केंद्र
+Comment[hr]=KDE pomoć
+Comment[hu]=KDE Segítség
+Comment[id]=Pusat Bantuan KDE
+Comment[is]=Hjálparkerfi KDE
+Comment[it]=La guida di KDE
+Comment[ja]=KDE ヘルプセンター
+Comment[ka]=KDE-ს დახმარების ცენტრი
+Comment[kk]=KDE анықтама орталығы
+Comment[km]=មជ្ឈមណ្ឌលជំនួយ​របស់ KDE
+Comment[ko]=KDE 도움말 센터
+Comment[lo]=ສູນຊ່ວຍເຫລືອຂອງ KDE
+Comment[lt]=KDE pagalbos centras
+Comment[lv]=KDE Palīdzības Centrs
+Comment[mk]=KDE Центарот за Помош
+Comment[mn]=КДЭ-Тусламжийн төв
+Comment[ms]=Pusat Bantuan KDE
+Comment[mt]=Ċentru tal-Għajnuna KDE
+Comment[nb]=KDE Hjelpesenter
+Comment[nds]=Dat KDE-Hülpzentrum
+Comment[ne]=केडीई मद्दत केन्द्र
+Comment[nl]=Het KDE-documentatiecentrum
+Comment[nn]=KDE Hjelpesenter
+Comment[nso]=Bogare bja Thuso ya KDE
+Comment[oc]=Lo centre d'ajuda KDE
+Comment[pa]=ਕੇਡੀਈ ਸਹਾਇਤਾ ਕੇਂਦਰ
+Comment[pl]=Centrum Pomocy KDE
+Comment[pt]=O Centro de Ajuda do KDE
+Comment[pt_BR]=Centro de Ajuda do KDE
+Comment[ro]=Centrul de ajutor al KDE
+Comment[ru]=Центр справки KDE
+Comment[rw]=KDE Ifashayobora Hagati
+Comment[se]=KDE veahkkeguovddáš
+Comment[sk]=KDE Centrum pomoci
+Comment[sl]=Središče pomoči za KDE
+Comment[sr]=KDE центар за помоћ
+Comment[sr@Latn]=KDE centar za pomoć
+Comment[sv]=KDE:s hjälpcentral
+Comment[ta]=KDE உதவி மையம்
+Comment[te]=కెడిఈ సహాయ కేంద్రం
+Comment[tg]=Маркази роҳнамои KDE
+Comment[th]=ศูนย์ช่วยเหลือของ KDE
+Comment[tr]=KDE Yardım Merkezi
+Comment[tt]=KDE Yärdäm Üzäge
+Comment[uk]=Центр довідок KDE
+Comment[uz]=KDE yordam markazi
+Comment[uz@cyrillic]=KDE ёрдам маркази
+Comment[ven]=Senthara ya thuso ya KDE
+Comment[vi]=Trung tâm Trợ giúp KDE
+Comment[wa]=Li Cinte d' aidance KDE
+Comment[xh]=Umbindi woncedo lwe KDE
+Comment[zh_CN]=KDE 帮助中心
+Comment[zh_TW]=KDE 求助中心
+Comment[zu]=Indawo Yosizi ye-KDE
+Icon=khelpcenter
+DocPath=khelpcenter/index.html
+Type=Service
+Terminal=false
+Exec=khelpcenter %u
+SwallowExec=
+SwallowTitle=
+X-KDE-StartupNotify=true
diff --git a/khelpcenter/khelpcenter.kcfg b/khelpcenter/khelpcenter.kcfg
new file mode 100644
index 00000000..0ece51e1
--- /dev/null
+++ b/khelpcenter/khelpcenter.kcfg
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <include>kstandarddirs.h</include>
+ <kcfgfile name="khelpcenterrc"/>
+
+ <group name="Search">
+ <entry type="Path" key="IndexDirectory">
+ <label>Path to index directory.</label>
+ <whatsthis>Path to directory containing search indices.</whatsthis>
+ <default code="true">KGlobal::dirs()->saveLocation("data", "khelpcenter/index/")</default>
+ </entry>
+
+ <entry type="Int" key="Method">
+ <default>0</default>
+ </entry>
+ <entry type="Int" key="MaxCount">
+ <default>0</default>
+ </entry>
+ </group>
+
+ <group name="Layout">
+ <entry type="Enum" key="CurrentTab">
+ <label>Currently visible navigator tab</label>
+ <choices>
+ <choice name="Content"/>
+ <choice name="Search"/>
+ <choice name="Glossary"/>
+ </choices>
+ <default>Content</default>
+ </entry>
+ </group>
+
+</kcfg>
diff --git a/khelpcenter/khelpcenterui.rc b/khelpcenter/khelpcenterui.rc
new file mode 100644
index 00000000..7dfcb2f2
--- /dev/null
+++ b/khelpcenter/khelpcenterui.rc
@@ -0,0 +1,53 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="khelpcenter" version="14">
+<MenuBar>
+ <Menu name="file" noMerge="1">
+ <text>&amp;File</text>
+ <Action name="printFrame" group="print" />
+ <Action name="show_search_stderr" />
+ <Separator />
+ <Action name="file_quit"/>
+ </Menu>
+ <Menu name="edit" noMerge="1">
+ <text>&amp;Edit</text>
+ <Action name="copy_text" />
+ <Separator />
+ <Action name="selectAll" />
+ <Separator />
+ <Action name="find" />
+ </Menu>
+ <Menu name="view" noMerge="1">
+ <text>&amp;View</text>
+ <Action name="viewDocumentSource" />
+ <Action name="setEncoding" />
+ </Menu>
+ <Menu name="go_web">
+ <text>&amp;Go</text>
+ <Action name="prevPage" />
+ <Action name="nextPage" />
+ <Separator />
+ <Action name="back" />
+ <Action name="forward" />
+ <Separator />
+ <Action name="lastsearch" />
+ </Menu>
+ <Menu name="settings">
+ <Action name="configure_fonts" append="save_merge"/>
+ <Action name="build_index" append="save_merge"/>
+ </Menu>
+</MenuBar>
+<ToolBar name="mainToolBar" noMerge="1">
+ <text>Main Toolbar</text>
+ <Action name="go_home" />
+ <Action name="back" />
+ <Action name="forward" />
+ <Separator />
+ <Action name="printFrame" />
+ <Separator />
+ <Action name="copy_text" />
+ <Action name="find" />
+ <Separator />
+ <Action name="incFontSizes" />
+ <Action name="decFontSizes" />
+</ToolBar>
+</kpartgui>
diff --git a/khelpcenter/mainwindow.cpp b/khelpcenter/mainwindow.cpp
new file mode 100644
index 00000000..4082b39d
--- /dev/null
+++ b/khelpcenter/mainwindow.cpp
@@ -0,0 +1,467 @@
+ /*
+ * This file is part of the KDE Help Center
+ *
+ * Copyright (C) 1999 Matthias Elter (me@kde.org)
+ * 2001 Stephan Kulow (coolo@kde.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "mainwindow.h"
+
+#include "history.h"
+#include "view.h"
+#include "searchengine.h"
+#include "fontdialog.h"
+#include "prefs.h"
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <dcopclient.h>
+#include <kiconloader.h>
+#include <kmimemagic.h>
+#include <krun.h>
+#include <kaboutdata.h>
+#include <kdebug.h>
+#include <khtmlview.h>
+#include <khtml_settings.h>
+#include <kaction.h>
+#include <kstatusbar.h>
+#include <kstdaccel.h>
+#include <kdialogbase.h>
+
+#include <qsplitter.h>
+#include <qtextedit.h>
+#include <qlayout.h>
+
+#include <stdlib.h>
+#include <assert.h>
+
+using namespace KHC;
+
+class LogDialog : public KDialogBase
+{
+ public:
+ LogDialog( QWidget *parent = 0 )
+ : KDialogBase( Plain, i18n("Search Error Log"), Ok, Ok, parent, 0,
+ false )
+ {
+ QFrame *topFrame = plainPage();
+
+ QBoxLayout *topLayout = new QVBoxLayout( topFrame );
+
+ mTextView = new QTextEdit( topFrame );
+ mTextView->setTextFormat( LogText );
+ topLayout->addWidget( mTextView );
+
+ resize( configDialogSize( "logdialog" ) );
+ }
+
+ ~LogDialog()
+ {
+ saveDialogSize( "logdialog" );
+ }
+
+ void setLog( const QString &log )
+ {
+ mTextView->setText( log );
+ }
+
+ private:
+ QTextEdit *mTextView;
+};
+
+
+MainWindow::MainWindow()
+ : KMainWindow(0, "MainWindow"), DCOPObject( "KHelpCenterIface" ),
+ mLogDialog( 0 )
+{
+ mSplitter = new QSplitter( this );
+
+ mDoc = new View( mSplitter, 0, this, 0, KHTMLPart::DefaultGUI, actionCollection() );
+ connect( mDoc, SIGNAL( setWindowCaption( const QString & ) ),
+ SLOT( setCaption( const QString & ) ) );
+ connect( mDoc, SIGNAL( setStatusBarText( const QString & ) ),
+ SLOT( statusBarMessage( const QString & ) ) );
+ connect( mDoc, SIGNAL( onURL( const QString & ) ),
+ SLOT( statusBarMessage( const QString & ) ) );
+ connect( mDoc, SIGNAL( started( KIO::Job * ) ),
+ SLOT( slotStarted( KIO::Job * ) ) );
+ connect( mDoc, SIGNAL( completed() ),
+ SLOT( documentCompleted() ) );
+ connect( mDoc, SIGNAL( searchResultCacheAvailable() ),
+ SLOT( enableLastSearchAction() ) );
+
+ connect( mDoc, SIGNAL( selectionChanged() ),
+ SLOT( enableCopyTextAction() ) );
+
+ statusBar()->insertItem(i18n("Preparing Index"), 0, 1);
+ statusBar()->setItemAlignment(0, AlignLeft | AlignVCenter);
+
+ connect( mDoc->browserExtension(),
+ SIGNAL( openURLRequest( const KURL &,
+ const KParts::URLArgs & ) ),
+ SLOT( slotOpenURLRequest( const KURL &,
+ const KParts::URLArgs & ) ) );
+
+ mNavigator = new Navigator( mDoc, mSplitter, "nav" );
+ connect( mNavigator, SIGNAL( itemSelected( const QString & ) ),
+ SLOT( viewUrl( const QString & ) ) );
+ connect( mNavigator, SIGNAL( glossSelected( const GlossaryEntry & ) ),
+ SLOT( slotGlossSelected( const GlossaryEntry & ) ) );
+
+ mSplitter->moveToFirst(mNavigator);
+ mSplitter->setResizeMode(mNavigator, QSplitter::KeepSize);
+ setCentralWidget( mSplitter );
+ QValueList<int> sizes;
+ sizes << 220 << 580;
+ mSplitter->setSizes(sizes);
+ setGeometry(366, 0, 800, 600);
+
+ KConfig *cfg = kapp->config();
+ {
+ KConfigGroupSaver groupSaver( cfg, "General" );
+ if ( cfg->readBoolEntry( "UseKonqSettings", true ) ) {
+ KConfig konqCfg( "konquerorrc" );
+ const_cast<KHTMLSettings *>( mDoc->settings() )->init( &konqCfg );
+ }
+ const int zoomFactor = cfg->readNumEntry( "Font zoom factor", 100 );
+ mDoc->setZoomFactor( zoomFactor );
+ }
+
+ setupActions();
+
+ actionCollection()->addDocCollection( mDoc->actionCollection() );
+
+ setupGUI(ToolBar | Keys | StatusBar | Create);
+ setAutoSaveSettings();
+
+ History::self().installMenuBarHook( this );
+
+ connect( &History::self(), SIGNAL( goInternalUrl( const KURL & ) ),
+ mNavigator, SLOT( openInternalUrl( const KURL & ) ) );
+ connect( &History::self(), SIGNAL( goUrl( const KURL & ) ),
+ mNavigator, SLOT( selectItem( const KURL & ) ) );
+
+ statusBarMessage(i18n("Ready"));
+ enableCopyTextAction();
+
+ readConfig();
+}
+
+MainWindow::~MainWindow()
+{
+ writeConfig();
+}
+
+void MainWindow::enableCopyTextAction()
+{
+ mCopyText->setEnabled( mDoc->hasSelection() );
+}
+
+void MainWindow::saveProperties( KConfig *config )
+{
+ kdDebug()<<"void MainWindow::saveProperties( KConfig *config )" << endl;
+ config->writePathEntry( "URL" , mDoc->baseURL().url() );
+}
+
+void MainWindow::readProperties( KConfig *config )
+{
+ kdDebug()<<"void MainWindow::readProperties( KConfig *config )" << endl;
+ mDoc->slotReload( KURL( config->readPathEntry( "URL" ) ) );
+}
+
+void MainWindow::readConfig()
+{
+ KConfig *config = KGlobal::config();
+ config->setGroup( "MainWindowState" );
+ QValueList<int> sizes = config->readIntListEntry( "Splitter" );
+ if ( sizes.count() == 2 ) {
+ mSplitter->setSizes( sizes );
+ }
+
+ mNavigator->readConfig();
+}
+
+void MainWindow::writeConfig()
+{
+ KConfig *config = KGlobal::config();
+ config->setGroup( "MainWindowState" );
+ config->writeEntry( "Splitter", mSplitter->sizes() );
+
+ mNavigator->writeConfig();
+
+ Prefs::writeConfig();
+}
+
+void MainWindow::setupActions()
+{
+ KStdAction::quit( this, SLOT( close() ), actionCollection() );
+ KStdAction::print( this, SLOT( print() ), actionCollection(),
+ "printFrame" );
+
+ KAction *prevPage = new KAction( i18n( "Previous Page" ), CTRL+Key_PageUp, mDoc, SLOT( prevPage() ),
+ actionCollection(), "prevPage" );
+ prevPage->setWhatsThis( i18n( "Moves to the previous page of the document" ) );
+
+ KAction *nextPage = new KAction( i18n( "Next Page" ), CTRL + Key_PageDown, mDoc, SLOT( nextPage() ),
+ actionCollection(), "nextPage" );
+ nextPage->setWhatsThis( i18n( "Moves to the next page of the document" ) );
+
+ KAction *home = KStdAction::home( this, SLOT( slotShowHome() ), actionCollection() );
+ home->setText(i18n("Table of &Contents"));
+ home->setToolTip(i18n("Table of contents"));
+ home->setWhatsThis(i18n("Go back to the table of contents"));
+
+ mCopyText = KStdAction::copy( this, SLOT(slotCopySelectedText()), actionCollection(), "copy_text");
+
+ mLastSearchAction = new KAction( i18n("&Last Search Result"), 0, this,
+ SLOT( slotLastSearch() ),
+ actionCollection(), "lastsearch" );
+ mLastSearchAction->setEnabled( false );
+
+ new KAction( i18n("Build Search Index..."), 0, mNavigator,
+ SLOT( showIndexDialog() ), actionCollection(), "build_index" );
+ KStdAction::keyBindings( guiFactory(), SLOT( configureShortcuts() ),
+ actionCollection() );
+
+ KConfig *cfg = KGlobal::config();
+ cfg->setGroup( "Debug" );
+ if ( cfg->readBoolEntry( "SearchErrorLog", false ) ) {
+ new KAction( i18n("Show Search Error Log"), 0, this,
+ SLOT( showSearchStderr() ), actionCollection(),
+ "show_search_stderr" );
+ }
+
+ History::self().setupActions( actionCollection() );
+
+ new KAction( i18n( "Configure Fonts..." ), KShortcut(), this, SLOT( slotConfigureFonts() ), actionCollection(), "configure_fonts" );
+ new KAction( i18n( "Increase Font Sizes" ), "viewmag+", KShortcut(), this, SLOT( slotIncFontSizes() ), actionCollection(), "incFontSizes" );
+ new KAction( i18n( "Decrease Font Sizes" ), "viewmag-", KShortcut(), this, SLOT( slotDecFontSizes() ), actionCollection(), "decFontSizes" );
+}
+
+void MainWindow::slotCopySelectedText()
+{
+ mDoc->copySelectedText();
+}
+
+void MainWindow::print()
+{
+ mDoc->view()->print();
+}
+
+void MainWindow::slotStarted(KIO::Job *job)
+{
+ if (job)
+ connect(job, SIGNAL(infoMessage( KIO::Job *, const QString &)),
+ SLOT(slotInfoMessage(KIO::Job *, const QString &)));
+
+ History::self().updateActions();
+}
+
+void MainWindow::goInternalUrl( const KURL &url )
+{
+ mDoc->closeURL();
+ slotOpenURLRequest( url, KParts::URLArgs() );
+}
+
+void MainWindow::slotOpenURLRequest( const KURL &url,
+ const KParts::URLArgs &args )
+{
+ kdDebug( 1400 ) << "MainWindow::slotOpenURLRequest(): " << url.url() << endl;
+
+ mNavigator->selectItem( url );
+ viewUrl( url, args );
+}
+
+void MainWindow::viewUrl( const QString &url )
+{
+ viewUrl( KURL( url ) );
+}
+
+void MainWindow::viewUrl( const KURL &url, const KParts::URLArgs &args )
+{
+ stop();
+
+ QString proto = url.protocol().lower();
+
+ if ( proto == "khelpcenter" ) {
+ History::self().createEntry();
+ mNavigator->openInternalUrl( url );
+ return;
+ }
+
+ bool own = false;
+
+ if ( proto == "help" || proto == "glossentry" || proto == "about" ||
+ proto == "man" || proto == "info" || proto == "cgi" ||
+ proto == "ghelp" )
+ own = true;
+ else if ( url.isLocalFile() ) {
+ KMimeMagicResult *res = KMimeMagic::self()->findFileType( url.path() );
+ if ( res->isValid() && res->accuracy() > 40
+ && res->mimeType() == "text/html" )
+ own = true;
+ }
+
+ if ( !own ) {
+ new KRun( url );
+ return;
+ }
+
+ History::self().createEntry();
+
+ mDoc->browserExtension()->setURLArgs( args );
+
+ if ( proto == QString::fromLatin1("glossentry") ) {
+ QString decodedEntryId = KURL::decode_string( url.encodedPathAndQuery() );
+ slotGlossSelected( mNavigator->glossEntry( decodedEntryId ) );
+ mNavigator->slotSelectGlossEntry( decodedEntryId );
+ } else {
+ mDoc->openURL( url );
+ }
+}
+
+void MainWindow::documentCompleted()
+{
+ kdDebug() << "MainWindow::documentCompleted" << endl;
+
+ History::self().updateCurrentEntry( mDoc );
+ History::self().updateActions();
+}
+
+void MainWindow::slotInfoMessage(KIO::Job *, const QString &m)
+{
+ statusBarMessage(m);
+}
+
+void MainWindow::statusBarMessage(const QString &m)
+{
+ statusBar()->changeItem(m, 0);
+}
+
+void MainWindow::openUrl( const QString &url )
+{
+ openUrl( KURL( url ) );
+}
+
+void MainWindow::openUrl( const QString &url, const QCString& startup_id )
+{
+ KStartupInfo::setNewStartupId( this, startup_id );
+ openUrl( KURL( url ) );
+}
+
+void MainWindow::openUrl( const KURL &url )
+{
+ if ( url.isEmpty() ) slotShowHome();
+ else {
+ mNavigator->selectItem( url );
+ viewUrl( url );
+ }
+}
+
+void MainWindow::slotGlossSelected(const GlossaryEntry &entry)
+{
+ kdDebug() << "MainWindow::slotGlossSelected()" << endl;
+
+ stop();
+ History::self().createEntry();
+ mDoc->begin( KURL( "help:/khelpcenter/glossary" ) );
+ mDoc->write( Glossary::entryToHtml( entry ) );
+ mDoc->end();
+}
+
+void MainWindow::stop()
+{
+ kdDebug() << "MainWindow::stop()" << endl;
+
+ mDoc->closeURL();
+ History::self().updateCurrentEntry( mDoc );
+}
+
+void MainWindow::showHome()
+{
+ slotShowHome();
+}
+
+void MainWindow::slotShowHome()
+{
+ viewUrl( mNavigator->homeURL() );
+ mNavigator->clearSelection();
+}
+
+void MainWindow::lastSearch()
+{
+ slotLastSearch();
+}
+
+void MainWindow::slotLastSearch()
+{
+ mDoc->lastSearch();
+}
+
+void MainWindow::enableLastSearchAction()
+{
+ mLastSearchAction->setEnabled( true );
+}
+
+void MainWindow::showSearchStderr()
+{
+ QString log = mNavigator->searchEngine()->errorLog();
+
+ if ( !mLogDialog ) {
+ mLogDialog = new LogDialog( this );
+ }
+
+ mLogDialog->setLog( log );
+ mLogDialog->show();
+ mLogDialog->raise();
+}
+
+void MainWindow::slotIncFontSizes()
+{
+ mDoc->slotIncFontSizes();
+ updateZoomActions();
+}
+
+void MainWindow::slotDecFontSizes()
+{
+ mDoc->slotDecFontSizes();
+ updateZoomActions();
+}
+
+void MainWindow::updateZoomActions()
+{
+ actionCollection()->action( "incFontSizes" )->setEnabled( mDoc->zoomFactor() + mDoc->zoomStepping() <= 300 );
+ actionCollection()->action( "decFontSizes" )->setEnabled( mDoc->zoomFactor() - mDoc->zoomStepping() >= 20 );
+
+ KConfig *cfg = kapp->config();
+ {
+ KConfigGroupSaver groupSaver( cfg, "General" );
+ cfg->writeEntry( "Font zoom factor", mDoc->zoomFactor() );
+ cfg->sync();
+ }
+}
+
+void MainWindow::slotConfigureFonts()
+{
+ FontDialog dlg( this );
+ if ( dlg.exec() == QDialog::Accepted )
+ mDoc->slotReload();
+}
+
+#include "mainwindow.moc"
+
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/mainwindow.h b/khelpcenter/mainwindow.h
new file mode 100644
index 00000000..aba2d342
--- /dev/null
+++ b/khelpcenter/mainwindow.h
@@ -0,0 +1,108 @@
+#ifndef __mainwindow_h__
+#define __mainwindow_h__
+
+#include <qptrlist.h>
+
+#include <kmainwindow.h>
+#include <kio/job.h>
+#include <kurl.h>
+#include <kparts/browserextension.h>
+#include <dcopclient.h>
+#include <dcopobject.h>
+
+#include "navigator.h"
+#include "glossary.h"
+
+class KHTMLPart;
+class QSplitter;
+
+class LogDialog;
+
+namespace KHC {
+
+class View;
+
+class MainWindow : public KMainWindow, public DCOPObject
+{
+ Q_OBJECT
+ K_DCOP
+ public:
+ MainWindow();
+ ~MainWindow();
+
+ k_dcop:
+ void openUrl( const QString &url );
+ void openUrl( const QString &url, const QCString& startup_id );
+ void showHome();
+ void lastSearch();
+
+ public slots:
+ void print();
+ void statusBarMessage(const QString &m);
+ void slotShowHome();
+ void slotLastSearch();
+ void showSearchStderr();
+ /**
+ Show document corresponding to given URL in viewer part.
+ */
+ void viewUrl( const KURL &url,
+ const KParts::URLArgs &args = KParts::URLArgs() );
+ /**
+ Show document corresponding to given URL in viewer part.
+ */
+ void viewUrl( const QString & );
+
+ /**
+ Open document corresponding to given URL, i.e. show it in the viewer part
+ and select the corresponding entry in the navigator widget.
+ */
+ void openUrl( const KURL &url );
+
+ protected:
+ void setupActions();
+
+ virtual void saveProperties( KConfig *config );
+ virtual void readProperties( KConfig *config );
+
+ void readConfig();
+ void writeConfig();
+
+ protected slots:
+ void enableLastSearchAction();
+ void enableCopyTextAction();
+
+ private:
+ void stop();
+
+ private slots:
+ void slotGlossSelected(const GlossaryEntry &entry);
+ void slotStarted(KIO::Job *job);
+ void slotInfoMessage(KIO::Job *, const QString &);
+ void goInternalUrl( const KURL & );
+ /**
+ This function is called when the user clicks on a link in the viewer part.
+ */
+ void slotOpenURLRequest( const KURL &url,
+ const KParts::URLArgs &args);
+ void documentCompleted();
+ void slotIncFontSizes();
+ void slotDecFontSizes();
+ void slotConfigureFonts();
+ void slotCopySelectedText();
+
+private:
+ void updateZoomActions();
+
+ QSplitter *mSplitter;
+ View *mDoc;
+ Navigator *mNavigator;
+
+ KAction *mLastSearchAction;
+ KAction *mCopyText;
+ LogDialog *mLogDialog;
+};
+
+}
+
+#endif
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/navigator.cpp b/khelpcenter/navigator.cpp
new file mode 100644
index 00000000..652bf899
--- /dev/null
+++ b/khelpcenter/navigator.cpp
@@ -0,0 +1,672 @@
+/*
+ * This file is part of the KDE Help Center
+ *
+ * Copyright (C) 1999 Matthias Elter (me@kde.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <qdir.h>
+#include <qfile.h>
+#include <qpixmap.h>
+#include <qstring.h>
+#include <qlabel.h>
+#include <qheader.h>
+#include <qdom.h>
+#include <qtextstream.h>
+#include <qregexp.h>
+#include <qlayout.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+#include <qtooltip.h>
+
+#include <kaction.h>
+#include <kapplication.h>
+#include <ksimpleconfig.h>
+#include <kstandarddirs.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <klistview.h>
+#include <kmessagebox.h>
+#include <kiconloader.h>
+#include <kprocio.h>
+#include <kcharsets.h>
+#include <kdialog.h>
+#include <kdesktopfile.h>
+#include <kprotocolinfo.h>
+#include <kservicegroup.h>
+
+#include "navigatoritem.h"
+#include "navigatorappitem.h"
+#include "searchwidget.h"
+#include "searchengine.h"
+#include "docmetainfo.h"
+#include "docentrytraverser.h"
+#include "glossary.h"
+#include "toc.h"
+#include "view.h"
+#include "infotree.h"
+#include "mainwindow.h"
+#include "plugintraverser.h"
+#include "scrollkeepertreebuilder.h"
+#include "kcmhelpcenter.h"
+#include "formatter.h"
+#include "history.h"
+#include "prefs.h"
+
+#include "navigator.h"
+
+using namespace KHC;
+
+Navigator::Navigator( View *view, QWidget *parent, const char *name )
+ : QWidget( parent, name ), mIndexDialog( 0 ),
+ mView( view ), mSelected( false )
+{
+ KConfig *config = kapp->config();
+ config->setGroup("General");
+ mShowMissingDocs = config->readBoolEntry("ShowMissingDocs",false);
+
+ mSearchEngine = new SearchEngine( view );
+ connect( mSearchEngine, SIGNAL( searchFinished() ),
+ SLOT( slotSearchFinished() ) );
+
+ DocMetaInfo::self()->scanMetaInfo();
+
+ QBoxLayout *topLayout = new QVBoxLayout( this );
+
+ mSearchFrame = new QFrame( this );
+ topLayout->addWidget( mSearchFrame );
+
+ QBoxLayout *searchLayout = new QHBoxLayout( mSearchFrame );
+ searchLayout->setSpacing( KDialog::spacingHint() );
+ searchLayout->setMargin( 6 );
+
+ QPushButton *clearButton = new QPushButton( mSearchFrame );
+ clearButton->setIconSet( KApplication::reverseLayout() ?
+ SmallIconSet( "clear_left" ) : SmallIconSet("locationbar_erase") );
+ searchLayout->addWidget( clearButton );
+ connect( clearButton, SIGNAL( clicked() ), SLOT( clearSearch() ) );
+ QToolTip::add( clearButton, i18n("Clear search") );
+
+ mSearchEdit = new QLineEdit( mSearchFrame );
+ searchLayout->addWidget( mSearchEdit );
+ connect( mSearchEdit, SIGNAL( returnPressed() ), SLOT( slotSearch() ) );
+ connect( mSearchEdit, SIGNAL( textChanged( const QString & ) ),
+ SLOT( checkSearchButton() ) );
+
+ mSearchButton = new QPushButton( i18n("&Search"), mSearchFrame );
+ searchLayout->addWidget( mSearchButton );
+ connect( mSearchButton, SIGNAL( clicked() ), SLOT( slotSearch() ) );
+
+ clearButton->setFixedHeight( mSearchButton->height() );
+
+ mTabWidget = new QTabWidget( this );
+ topLayout->addWidget( mTabWidget );
+ connect( mTabWidget, SIGNAL( currentChanged( QWidget * ) ),
+ SLOT( slotTabChanged( QWidget * ) ) );
+
+ setupContentsTab();
+ setupGlossaryTab();
+ setupSearchTab();
+
+ insertPlugins();
+
+ if ( !mSearchEngine->initSearchHandlers() ) {
+ hideSearch();
+ } else {
+ mSearchWidget->updateScopeList();
+ mSearchWidget->readConfig( KGlobal::config() );
+ }
+}
+
+Navigator::~Navigator()
+{
+ delete mSearchEngine;
+}
+
+SearchEngine *Navigator::searchEngine() const
+{
+ return mSearchEngine;
+}
+
+Formatter *Navigator::formatter() const
+{
+ return mView->formatter();
+}
+
+bool Navigator::showMissingDocs() const
+{
+ return mShowMissingDocs;
+}
+
+void Navigator::setupContentsTab()
+{
+ mContentsTree = new KListView( mTabWidget );
+ mContentsTree->setFrameStyle(QFrame::Panel | QFrame::Sunken);
+ mContentsTree->addColumn(QString::null);
+ mContentsTree->setAllColumnsShowFocus(true);
+ mContentsTree->header()->hide();
+ mContentsTree->setRootIsDecorated(false);
+ mContentsTree->setSorting(-1, false);
+
+ connect(mContentsTree, SIGNAL(clicked(QListViewItem*)),
+ SLOT(slotItemSelected(QListViewItem*)));
+ connect(mContentsTree, SIGNAL(returnPressed(QListViewItem*)),
+ SLOT(slotItemSelected(QListViewItem*)));
+ mTabWidget->addTab(mContentsTree, i18n("&Contents"));
+}
+
+void Navigator::setupSearchTab()
+{
+ mSearchWidget = new SearchWidget( mSearchEngine, mTabWidget );
+ connect( mSearchWidget, SIGNAL( searchResult( const QString & ) ),
+ SLOT( slotShowSearchResult( const QString & ) ) );
+ connect( mSearchWidget, SIGNAL( scopeCountChanged( int ) ),
+ SLOT( checkSearchButton() ) );
+ connect( mSearchWidget, SIGNAL( showIndexDialog() ),
+ SLOT( showIndexDialog() ) );
+
+ mTabWidget->addTab( mSearchWidget, i18n("Search Options"));
+}
+
+void Navigator::setupGlossaryTab()
+{
+ mGlossaryTree = new Glossary( mTabWidget );
+ connect( mGlossaryTree, SIGNAL( entrySelected( const GlossaryEntry & ) ),
+ this, SIGNAL( glossSelected( const GlossaryEntry & ) ) );
+ mTabWidget->addTab( mGlossaryTree, i18n( "G&lossary" ) );
+}
+
+void Navigator::insertPlugins()
+{
+ PluginTraverser t( this, mContentsTree );
+ DocMetaInfo::self()->traverseEntries( &t );
+
+#if 0
+ kdDebug( 1400 ) << "<docmetainfo>" << endl;
+ DocEntry::List entries = DocMetaInfo::self()->docEntries();
+ DocEntry::List::ConstIterator it;
+ for( it = entries.begin(); it != entries.end(); ++it ) {
+ (*it)->dump();
+ }
+ kdDebug( 1400 ) << "</docmetainfo>" << endl;
+#endif
+}
+
+void Navigator::insertParentAppDocs( const QString &name, NavigatorItem *topItem )
+{
+ kdDebug(1400) << "Requested plugin documents for ID " << name << endl;
+
+ KServiceGroup::Ptr grp = KServiceGroup::childGroup( name );
+ if ( !grp )
+ return;
+
+ KServiceGroup::List entries = grp->entries();
+ KServiceGroup::List::ConstIterator it = entries.begin();
+ KServiceGroup::List::ConstIterator end = entries.end();
+ for ( ; it != end; ++it ) {
+ QString desktopFile = ( *it )->entryPath();
+ if ( QDir::isRelativePath( desktopFile ) )
+ desktopFile = locate( "apps", desktopFile );
+ createItemFromDesktopFile( topItem, desktopFile );
+ }
+}
+
+void Navigator::insertIOSlaveDocs( const QString &name, NavigatorItem *topItem )
+{
+ kdDebug(1400) << "Requested IOSlave documents for ID " << name << endl;
+
+#if KDE_IS_VERSION( 3, 1, 90 )
+ QStringList list = KProtocolInfo::protocols();
+ list.sort();
+
+ NavigatorItem *prevItem = 0;
+ for ( QStringList::ConstIterator it = list.begin(); it != list.end(); ++it )
+ {
+ QString docPath = KProtocolInfo::docPath(*it);
+ if ( !docPath.isNull() )
+ {
+ // First parameter is ignored if second is an absolute path
+ KURL url(KURL("help:/"), docPath);
+ QString icon = KProtocolInfo::icon(*it);
+ if ( icon.isEmpty() ) icon = "document2";
+ DocEntry *entry = new DocEntry( *it, url.url(), icon );
+ NavigatorItem *item = new NavigatorItem( entry, topItem, prevItem );
+ prevItem = item;
+ item->setAutoDeleteDocEntry( true );
+ }
+ }
+#else
+ Q_UNUSED( topItem );
+#endif
+}
+
+void Navigator::insertAppletDocs( NavigatorItem *topItem )
+{
+ QDir appletDir( locate( "data", QString::fromLatin1( "kicker/applets/" ) ) );
+ appletDir.setNameFilter( QString::fromLatin1( "*.desktop" ) );
+
+ QStringList files = appletDir.entryList( QDir::Files | QDir::Readable );
+ QStringList::ConstIterator it = files.begin();
+ QStringList::ConstIterator end = files.end();
+ for ( ; it != end; ++it )
+ createItemFromDesktopFile( topItem, appletDir.absPath() + "/" + *it );
+}
+
+void Navigator::createItemFromDesktopFile( NavigatorItem *topItem,
+ const QString &file )
+{
+ KDesktopFile desktopFile( file );
+ QString docPath = desktopFile.readDocPath();
+ if ( !docPath.isNull() ) {
+ // First parameter is ignored if second is an absolute path
+ KURL url(KURL("help:/"), docPath);
+ QString icon = desktopFile.readIcon();
+ if ( icon.isEmpty() ) icon = "document2";
+ DocEntry *entry = new DocEntry( desktopFile.readName(), url.url(), icon );
+ NavigatorItem *item = new NavigatorItem( entry, topItem );
+ item->setAutoDeleteDocEntry( true );
+ }
+}
+
+void Navigator::insertInfoDocs( NavigatorItem *topItem )
+{
+ InfoTree *infoTree = new InfoTree( this );
+ infoTree->build( topItem );
+}
+
+NavigatorItem *Navigator::insertScrollKeeperDocs( NavigatorItem *topItem,
+ NavigatorItem *after )
+{
+ ScrollKeeperTreeBuilder *builder = new ScrollKeeperTreeBuilder( this );
+ return builder->build( topItem, after );
+}
+
+void Navigator::selectItem( const KURL &url )
+{
+ kdDebug() << "Navigator::selectItem(): " << url.url() << endl;
+
+ if ( url.url() == "khelpcenter:home" ) {
+ clearSelection();
+ return;
+ }
+
+ // help:/foo&anchor=bar gets redirected to help:/foo#bar
+ // Make sure that we match both the original URL as well as
+ // its counterpart.
+ KURL alternativeURL = url;
+ if (url.hasRef())
+ {
+ alternativeURL.setQuery("anchor="+url.ref());
+ alternativeURL.setRef(QString::null);
+ }
+
+ // If the navigator already has the given URL selected, do nothing.
+ NavigatorItem *item;
+ item = static_cast<NavigatorItem *>( mContentsTree->selectedItem() );
+ if ( item && mSelected ) {
+ KURL currentURL ( item->entry()->url() );
+ if ( (currentURL == url) || (currentURL == alternativeURL) ) {
+ kdDebug() << "URL already shown." << endl;
+ return;
+ }
+ }
+
+ // First, populate the NavigatorAppItems if we don't want the home page
+ if ( url != homeURL() ) {
+ for ( QListViewItem *item = mContentsTree->firstChild(); item;
+ item = item->nextSibling() ) {
+ NavigatorAppItem *appItem = dynamic_cast<NavigatorAppItem *>( item );
+ if ( appItem ) appItem->populate( true /* recursive */ );
+ }
+ }
+
+ QListViewItemIterator it( mContentsTree );
+ while ( it.current() ) {
+ NavigatorItem *item = static_cast<NavigatorItem *>( it.current() );
+ KURL itemUrl( item->entry()->url() );
+ if ( (itemUrl == url) || (itemUrl == alternativeURL) ) {
+ mContentsTree->setCurrentItem( item );
+ // If the current item was not selected and remained unchanged it
+ // needs to be explicitly selected
+ mContentsTree->setSelected(item, true);
+ item->setOpen( true );
+ mContentsTree->ensureItemVisible( item );
+ break;
+ }
+ ++it;
+ }
+ if ( !it.current() ) {
+ clearSelection();
+ } else {
+ mSelected = true;
+ }
+}
+
+void Navigator::clearSelection()
+{
+ mContentsTree->clearSelection();
+ mSelected = false;
+}
+
+void Navigator::slotItemSelected( QListViewItem *currentItem )
+{
+ if ( !currentItem ) return;
+
+ mSelected = true;
+
+ NavigatorItem *item = static_cast<NavigatorItem *>( currentItem );
+
+ kdDebug(1400) << "Navigator::slotItemSelected(): " << item->entry()->name()
+ << endl;
+
+ if ( item->childCount() > 0 || item->isExpandable() )
+ item->setOpen( !item->isOpen() );
+
+ KURL url ( item->entry()->url() );
+
+ if ( url.protocol() == "khelpcenter" ) {
+ mView->closeURL();
+ History::self().updateCurrentEntry( mView );
+ History::self().createEntry();
+ showOverview( item, url );
+ } else {
+ if ( url.protocol() == "help" ) {
+ kdDebug( 1400 ) << "slotItemSelected(): Got help URL " << url.url()
+ << endl;
+ if ( !item->toc() ) {
+ TOC *tocTree = item->createTOC();
+ kdDebug( 1400 ) << "slotItemSelected(): Trying to build TOC for "
+ << item->entry()->name() << endl;
+ tocTree->setApplication( url.directory() );
+ QString doc = View::langLookup( url.path() );
+ // Enforce the original .docbook version, in case langLookup returns a
+ // cached version
+ if ( !doc.isNull() ) {
+ int pos = doc.find( ".html" );
+ if ( pos >= 0 ) {
+ doc.replace( pos, 5, ".docbook" );
+ }
+ kdDebug( 1400 ) << "slotItemSelected(): doc = " << doc << endl;
+
+ tocTree->build( doc );
+ }
+ }
+ }
+ emit itemSelected( url.url() );
+ }
+
+ mLastUrl = url;
+}
+
+void Navigator::openInternalUrl( const KURL &url )
+{
+ if ( url.url() == "khelpcenter:home" ) {
+ clearSelection();
+ showOverview( 0, url );
+ return;
+ }
+
+ selectItem( url );
+ if ( !mSelected ) return;
+
+ NavigatorItem *item =
+ static_cast<NavigatorItem *>( mContentsTree->currentItem() );
+
+ if ( item ) showOverview( item, url );
+}
+
+void Navigator::showOverview( NavigatorItem *item, const KURL &url )
+{
+ mView->beginInternal( url );
+
+ QString fileName = locate( "data", "khelpcenter/index.html.in" );
+ if ( fileName.isEmpty() )
+ return;
+
+ QFile file( fileName );
+
+ if ( !file.open( IO_ReadOnly ) )
+ return;
+
+ QTextStream stream( &file );
+ QString res = stream.read();
+
+ QString title,name,content;
+ uint childCount;
+
+ if ( item ) {
+ title = item->entry()->name();
+ name = item->entry()->name();
+
+ QString info = item->entry()->info();
+ if ( !info.isEmpty() ) content = "<p>" + info + "</p>\n";
+
+ childCount = item->childCount();
+ } else {
+ title = i18n("Start Page");
+ name = i18n("KDE Help Center");
+
+ childCount = mContentsTree->childCount();
+ }
+
+ if ( childCount > 0 ) {
+ QListViewItem *child;
+ if ( item ) child = item->firstChild();
+ else child = mContentsTree->firstChild();
+
+ mDirLevel = 0;
+
+ content += createChildrenList( child );
+ }
+ else
+ content += "<p></p>";
+
+ res = res.arg(title).arg(name).arg(content);
+
+ mView->write( res );
+
+ mView->end();
+}
+
+QString Navigator::createChildrenList( QListViewItem *child )
+{
+ ++mDirLevel;
+
+ QString t;
+
+ t += "<ul>\n";
+
+ while ( child ) {
+ NavigatorItem *childItem = static_cast<NavigatorItem *>( child );
+
+ DocEntry *e = childItem->entry();
+
+ t += "<li><a href=\"" + e->url() + "\">";
+ if ( e->isDirectory() ) t += "<b>";
+ t += e->name();
+ if ( e->isDirectory() ) t += "</b>";
+ t += "</a>";
+
+ if ( !e->info().isEmpty() ) {
+ t += "<br>" + e->info();
+ }
+
+ t += "</li>\n";
+
+ if ( childItem->childCount() > 0 && mDirLevel < 2 ) {
+ t += createChildrenList( childItem->firstChild() );
+ }
+
+ child = child->nextSibling();
+ }
+
+ t += "</ul>\n";
+
+ --mDirLevel;
+
+ return t;
+}
+
+void Navigator::slotSearch()
+{
+ kdDebug(1400) << "Navigator::slotSearch()" << endl;
+
+ if ( !checkSearchIndex() ) return;
+
+ if ( mSearchEngine->isRunning() ) return;
+
+ QString words = mSearchEdit->text();
+ QString method = mSearchWidget->method();
+ int pages = mSearchWidget->pages();
+ QString scope = mSearchWidget->scope();
+
+ kdDebug(1400) << "Navigator::slotSearch() words: " << words << endl;
+ kdDebug(1400) << "Navigator::slotSearch() scope: " << scope << endl;
+
+ if ( words.isEmpty() || scope.isEmpty() ) return;
+
+ // disable search Button during searches
+ mSearchButton->setEnabled(false);
+ QApplication::setOverrideCursor(waitCursor);
+
+ if ( !mSearchEngine->search( words, method, pages, scope ) ) {
+ slotSearchFinished();
+ KMessageBox::sorry( this, i18n("Unable to run search program.") );
+ }
+}
+
+void Navigator::slotShowSearchResult( const QString &url )
+{
+ QString u = url;
+ u.replace( "%k", mSearchEdit->text() );
+
+ emit itemSelected( u );
+}
+
+void Navigator::slotSearchFinished()
+{
+ mSearchButton->setEnabled(true);
+ QApplication::restoreOverrideCursor();
+
+ kdDebug( 1400 ) << "Search finished." << endl;
+}
+
+void Navigator::checkSearchButton()
+{
+ mSearchButton->setEnabled( !mSearchEdit->text().isEmpty() &&
+ mSearchWidget->scopeCount() > 0 );
+ mTabWidget->showPage( mSearchWidget );
+}
+
+void Navigator::hideSearch()
+{
+ mSearchFrame->hide();
+ mTabWidget->removePage( mSearchWidget );
+}
+
+bool Navigator::checkSearchIndex()
+{
+ KConfig *cfg = KGlobal::config();
+ cfg->setGroup( "Search" );
+ if ( cfg->readBoolEntry( "IndexExists", false ) ) return true;
+
+ if ( mIndexDialog && mIndexDialog->isShown() ) return true;
+
+ QString text = i18n( "A search index does not yet exist. Do you want "
+ "to create the index now?" );
+
+ int result = KMessageBox::questionYesNo( this, text, QString::null,
+ i18n("Create"),
+ i18n("Do Not Create"),
+ "indexcreation" );
+ if ( result == KMessageBox::Yes ) {
+ showIndexDialog();
+ return false;
+ }
+
+ return true;
+}
+
+void Navigator::slotTabChanged( QWidget *wid )
+{
+ if ( wid == mSearchWidget ) checkSearchIndex();
+}
+
+void Navigator::slotSelectGlossEntry( const QString &id )
+{
+ mGlossaryTree->slotSelectGlossEntry( id );
+}
+
+KURL Navigator::homeURL()
+{
+ if ( !mHomeUrl.isEmpty() ) return mHomeUrl;
+
+ KConfig *cfg = KGlobal::config();
+ // We have to reparse the configuration here in order to get a
+ // language-specific StartUrl, e.g. "StartUrl[de]".
+ cfg->reparseConfiguration();
+ cfg->setGroup( "General" );
+ mHomeUrl = cfg->readPathEntry( "StartUrl", "khelpcenter:home" );
+ return mHomeUrl;
+}
+
+void Navigator::showIndexDialog()
+{
+ if ( !mIndexDialog ) {
+ mIndexDialog = new KCMHelpCenter( mSearchEngine, this );
+ connect( mIndexDialog, SIGNAL( searchIndexUpdated() ), mSearchWidget,
+ SLOT( updateScopeList() ) );
+ }
+ mIndexDialog->show();
+ mIndexDialog->raise();
+}
+
+void Navigator::readConfig()
+{
+ if ( Prefs::currentTab() == Prefs::Search ) {
+ mTabWidget->showPage( mSearchWidget );
+ } else if ( Prefs::currentTab() == Prefs::Glossary ) {
+ mTabWidget->showPage( mGlossaryTree );
+ } else {
+ mTabWidget->showPage( mContentsTree );
+ }
+}
+
+void Navigator::writeConfig()
+{
+ if ( mTabWidget->currentPage() == mSearchWidget ) {
+ Prefs::setCurrentTab( Prefs::Search );
+ } else if ( mTabWidget->currentPage() == mGlossaryTree ) {
+ Prefs::setCurrentTab( Prefs::Glossary );
+ } else {
+ Prefs::setCurrentTab( Prefs::Content );
+ }
+}
+
+void Navigator::clearSearch()
+{
+ mSearchEdit->setText( QString::null );
+}
+
+#include "navigator.moc"
+
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/navigator.h b/khelpcenter/navigator.h
new file mode 100644
index 00000000..5e28c046
--- /dev/null
+++ b/khelpcenter/navigator.h
@@ -0,0 +1,153 @@
+/*
+ * This file is part of the KDE Help Center
+ *
+ * Copyright (C) 1999 Matthias Elter (me@kde.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __navigator_h__
+#define __navigator_h__
+
+#include "glossary.h"
+
+#include <klistview.h>
+#include <kurl.h>
+
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qtimer.h>
+#include <qptrlist.h>
+#include <qtabwidget.h>
+#include <qlistview.h>
+#include <qdict.h>
+
+class QPushButton;
+
+class KListView;
+class KService;
+class KProcess;
+class KProcIO;
+
+class KCMHelpCenter;
+
+namespace KHC {
+
+class NavigatorItem;
+class Navigator;
+class View;
+class SearchEngine;
+class SearchWidget;
+class Formatter;
+
+class Navigator : public QWidget
+{
+ Q_OBJECT
+ public:
+ Navigator(View *, QWidget *parent=0, const char *name=0);
+ virtual ~Navigator();
+
+ KURL homeURL();
+
+ SearchEngine *searchEngine() const;
+ Formatter *formatter() const;
+
+ const GlossaryEntry &glossEntry(const QString &term) const { return mGlossaryTree->entry( term ); }
+
+ void insertParentAppDocs( const QString &name, NavigatorItem *parent );
+ void insertAppletDocs( NavigatorItem *parent );
+ NavigatorItem *insertScrollKeeperDocs( NavigatorItem *parentItem,
+ NavigatorItem *after );
+ void insertInfoDocs( NavigatorItem *parentItem );
+ void insertIOSlaveDocs(const QString &, NavigatorItem*parent);
+
+ void createItemFromDesktopFile( NavigatorItem *item, const QString &name );
+
+ bool showMissingDocs() const;
+
+ void clearSelection();
+
+ void showOverview( NavigatorItem *item, const KURL &url );
+
+ void readConfig();
+ void writeConfig();
+
+ public slots:
+ void openInternalUrl( const KURL &url );
+ void slotItemSelected(QListViewItem* index);
+ void slotSearch();
+ void slotShowSearchResult( const QString & );
+ void slotSelectGlossEntry( const QString &id );
+ void selectItem( const KURL &url );
+ void showIndexDialog();
+
+ signals:
+ void itemSelected(const QString& itemURL);
+ void glossSelected(const GlossaryEntry &entry);
+
+ protected slots:
+ void slotSearchFinished();
+ void slotTabChanged( QWidget * );
+ void checkSearchButton();
+
+ bool checkSearchIndex();
+
+ void clearSearch();
+
+ protected:
+ QString createChildrenList( QListViewItem *child );
+
+ private:
+ void setupContentsTab();
+ void setupIndexTab();
+ void setupSearchTab();
+ void setupGlossaryTab();
+
+ void insertPlugins();
+ void hideSearch();
+
+ KListView *mContentsTree;
+ Glossary *mGlossaryTree;
+
+ SearchWidget *mSearchWidget;
+ KCMHelpCenter *mIndexDialog;
+
+ QTabWidget *mTabWidget;
+
+ QFrame *mSearchFrame;
+ QLineEdit *mSearchEdit;
+ QPushButton *mSearchButton;
+
+ QPtrList<NavigatorItem> manualItems, pluginItems;
+
+ bool mShowMissingDocs;
+
+ SearchEngine *mSearchEngine;
+
+ View *mView;
+
+ KURL mHomeUrl;
+
+ bool mSelected;
+
+ KURL mLastUrl;
+
+ int mDirLevel;
+};
+
+}
+
+#endif
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/navigatorappitem.cpp b/khelpcenter/navigatorappitem.cpp
new file mode 100644
index 00000000..ca1dabe1
--- /dev/null
+++ b/khelpcenter/navigatorappitem.cpp
@@ -0,0 +1,147 @@
+/*
+ * This file is part of the KDE Help Center
+ *
+ * Copyright (C) 2001 Waldo Bastian <bastian@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "navigatorappitem.h"
+
+#include "docentry.h"
+
+#include <kdebug.h>
+#include <kservicegroup.h>
+
+using namespace KHC;
+
+NavigatorAppItem::NavigatorAppItem( DocEntry *entry, QListView *parent,
+ const QString &relPath )
+ : NavigatorItem( entry, parent ),
+ mRelpath( relPath ),
+ mPopulated( false )
+{
+ setExpandable( true );
+}
+
+NavigatorAppItem::NavigatorAppItem( DocEntry *entry, QListViewItem *parent,
+ const QString &relPath )
+ : NavigatorItem( entry, parent ),
+ mRelpath( relPath ),
+ mPopulated( false )
+{
+ setExpandable( true );
+}
+
+NavigatorAppItem::NavigatorAppItem( DocEntry *entry, QListView *parent,
+ QListViewItem *after )
+ : NavigatorItem( entry, parent, after ),
+ mPopulated( false )
+{
+ setExpandable( true );
+}
+
+NavigatorAppItem::NavigatorAppItem( DocEntry *entry, QListViewItem *parent,
+ QListViewItem *after )
+ : NavigatorItem( entry, parent, after ),
+ mPopulated( false )
+{
+ setExpandable( true );
+}
+
+void NavigatorAppItem::setRelpath( const QString &relpath )
+{
+ mRelpath = relpath;
+}
+
+void NavigatorAppItem::setOpen(bool open)
+{
+ kdDebug() << "NavigatorAppItem::setOpen()" << endl;
+
+ if ( open && (childCount() == 0) && !mPopulated )
+ {
+ kdDebug() << "NavigatorAppItem::setOpen(" << this << ", "
+ << mRelpath << ")" << endl;
+ populate();
+ }
+ QListViewItem::setOpen(open);
+}
+
+void NavigatorAppItem::populate( bool recursive )
+{
+ if ( mPopulated ) return;
+
+ KServiceGroup::Ptr root = KServiceGroup::group(mRelpath);
+ if ( !root ) {
+ kdWarning() << "No Service groups\n";
+ return;
+ }
+ KServiceGroup::List list = root->entries();
+
+
+ for ( KServiceGroup::List::ConstIterator it = list.begin();
+ it != list.end(); ++it )
+ {
+ KSycocaEntry * e = *it;
+ KService::Ptr s;
+ NavigatorItem *item;
+ KServiceGroup::Ptr g;
+ QString url;
+
+ switch ( e->sycocaType() ) {
+ case KST_KService:
+ {
+ s = static_cast<KService*>(e);
+ url = documentationURL( s );
+ if ( !url.isEmpty() ) {
+ DocEntry *entry = new DocEntry( s->name(), url, s->icon() );
+ item = new NavigatorItem( entry, this );
+ item->setAutoDeleteDocEntry( true );
+ item->setExpandable( true );
+ }
+ break;
+ }
+ case KST_KServiceGroup:
+ {
+ g = static_cast<KServiceGroup*>(e);
+ if ( ( g->childCount() == 0 ) || g->name().startsWith( "." ) )
+ continue;
+ DocEntry *entry = new DocEntry( g->caption(), "", g->icon() );
+ NavigatorAppItem *appItem;
+ appItem = new NavigatorAppItem( entry, this, g->relPath() );
+ appItem->setAutoDeleteDocEntry( true );
+ if ( recursive ) appItem->populate( recursive );
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ sortChildItems( 0, true /* ascending */ );
+ mPopulated = true;
+}
+
+QString NavigatorAppItem::documentationURL( KService *s )
+{
+ QString docPath = s->property( "DocPath" ).toString();
+ if ( docPath.isEmpty() )
+ return QString::null;
+
+ if ( docPath.startsWith( "file:") || docPath.startsWith( "http:" ) )
+ return docPath;
+
+ return QString( "help:/" ) + docPath;
+}
+
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/navigatorappitem.h b/khelpcenter/navigatorappitem.h
new file mode 100644
index 00000000..8690c52e
--- /dev/null
+++ b/khelpcenter/navigatorappitem.h
@@ -0,0 +1,58 @@
+/*
+ * navigatorappitem.h - part of the KDE Help Center
+ *
+ * Copyright (C) 2001 Waldo Bastian <bastian@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __navigatorappitem_h___
+#define __navigatorappitem_h___
+
+#include "navigatoritem.h"
+
+class KService;
+
+namespace KHC {
+
+class NavigatorAppItem : public NavigatorItem
+{
+ public:
+ NavigatorAppItem( DocEntry *entry, QListView *parent,
+ const QString &relPath );
+ NavigatorAppItem( DocEntry *entry, QListViewItem *parent,
+ const QString &relPath );
+
+ NavigatorAppItem( DocEntry *entry, QListView *parent,
+ QListViewItem *after );
+ NavigatorAppItem( DocEntry *entry, QListViewItem *parent,
+ QListViewItem *after );
+
+ void setRelpath( const QString & );
+
+ virtual void setOpen(bool);
+ void populate( bool recursive = false );
+
+ protected:
+ QString documentationURL( KService *s );
+
+ private:
+ QString mRelpath;
+ bool mPopulated;
+};
+
+}
+
+#endif
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/navigatoritem.cpp b/khelpcenter/navigatoritem.cpp
new file mode 100644
index 00000000..d2ad548b
--- /dev/null
+++ b/khelpcenter/navigatoritem.cpp
@@ -0,0 +1,105 @@
+/*
+ * This file is part of the KDE Help Center
+ *
+ * Copyright (C) 1999 Matthias Elter (me@kde.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "navigatoritem.h"
+
+#include "toc.h"
+#include "docentry.h"
+
+#include <kdebug.h>
+#include <kiconloader.h>
+
+using namespace KHC;
+
+NavigatorItem::NavigatorItem( DocEntry *entry, QListView *parent,
+ QListViewItem *after )
+ : QListViewItem( parent, after )
+{
+ init( entry );
+}
+
+NavigatorItem::NavigatorItem( DocEntry *entry, QListViewItem *parent,
+ QListViewItem *after )
+ : QListViewItem( parent, after )
+{
+ init( entry );
+}
+
+NavigatorItem::NavigatorItem( DocEntry *entry, QListView *parent )
+ : QListViewItem( parent )
+{
+ init( entry );
+}
+
+NavigatorItem::NavigatorItem( DocEntry *entry, QListViewItem *parent )
+ : QListViewItem( parent )
+{
+ init( entry );
+}
+
+NavigatorItem::~NavigatorItem()
+{
+ delete mToc;
+
+ if ( mAutoDeleteDocEntry ) delete mEntry;
+}
+
+void NavigatorItem::init( DocEntry *entry )
+{
+ mEntry = entry;
+ mAutoDeleteDocEntry = false;
+ mToc = 0;
+
+ updateItem();
+}
+
+DocEntry *NavigatorItem::entry() const
+{
+ return mEntry;
+}
+
+void NavigatorItem::setAutoDeleteDocEntry( bool enabled )
+{
+ mAutoDeleteDocEntry = enabled;
+}
+
+void NavigatorItem::updateItem()
+{
+ setText( 0, entry()->name() );
+ setPixmap( 0, SmallIcon( entry()->icon() ) );
+}
+
+TOC *NavigatorItem::createTOC()
+{
+ mToc = new TOC( this );
+ return mToc;
+}
+
+void NavigatorItem::setOpen( bool open )
+{
+ QListViewItem::setOpen( open );
+
+ if ( entry()->icon().isEmpty() || entry()->icon() == "contents2" ) {
+ if ( open && childCount() > 0 ) setPixmap( 0, SmallIcon( "contents" ) );
+ else setPixmap( 0, SmallIcon( "contents2" ) );
+ }
+}
+
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/navigatoritem.h b/khelpcenter/navigatoritem.h
new file mode 100644
index 00000000..4337a47f
--- /dev/null
+++ b/khelpcenter/navigatoritem.h
@@ -0,0 +1,68 @@
+/*
+ * navigatoritem.h - part of the KDE Help Center
+ *
+ * Copyright (C) 1999 Matthias Elter (me@kde.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef KHC_NAVIGATORITEM_H
+#define KHC_NAVIGATORITEM_H
+
+#include <qlistview.h>
+
+namespace KHC {
+
+class TOC;
+class DocEntry;
+
+class NavigatorItem : public QListViewItem
+{
+ public:
+ NavigatorItem( DocEntry *entry, QListView *parent );
+ NavigatorItem( DocEntry *entry, QListViewItem *parent );
+
+ NavigatorItem( DocEntry *entry, QListView *parent,
+ QListViewItem *after );
+ NavigatorItem( DocEntry *entry, QListViewItem *parent,
+ QListViewItem *after );
+
+ ~NavigatorItem();
+
+ DocEntry *entry() const;
+
+ void setAutoDeleteDocEntry( bool );
+
+ void updateItem();
+
+ TOC *toc() const { return mToc; }
+
+ TOC *createTOC();
+
+ void setOpen( bool open );
+
+ private:
+ void init( DocEntry * );
+
+ TOC *mToc;
+
+ DocEntry *mEntry;
+ bool mAutoDeleteDocEntry;
+};
+
+}
+
+#endif
+
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/pics/Makefile.am b/khelpcenter/pics/Makefile.am
new file mode 100644
index 00000000..dcfadd16
--- /dev/null
+++ b/khelpcenter/pics/Makefile.am
@@ -0,0 +1,6 @@
+
+KDE_ICON = khelpcenter
+
+khelpcenter_ICON = helpdoc helpbook helpbook_open
+khelpcenterdir = $(kde_datadir)/khelpcenter/icons
+
diff --git a/khelpcenter/pics/hi128-app-khelpcenter.png b/khelpcenter/pics/hi128-app-khelpcenter.png
new file mode 100644
index 00000000..949fd3dc
--- /dev/null
+++ b/khelpcenter/pics/hi128-app-khelpcenter.png
Binary files differ
diff --git a/khelpcenter/pics/hi16-app-khelpcenter.png b/khelpcenter/pics/hi16-app-khelpcenter.png
new file mode 100644
index 00000000..d242b4b3
--- /dev/null
+++ b/khelpcenter/pics/hi16-app-khelpcenter.png
Binary files differ
diff --git a/khelpcenter/pics/hi22-app-khelpcenter.png b/khelpcenter/pics/hi22-app-khelpcenter.png
new file mode 100644
index 00000000..71f59060
--- /dev/null
+++ b/khelpcenter/pics/hi22-app-khelpcenter.png
Binary files differ
diff --git a/khelpcenter/pics/hi32-app-khelpcenter.png b/khelpcenter/pics/hi32-app-khelpcenter.png
new file mode 100644
index 00000000..79dd450e
--- /dev/null
+++ b/khelpcenter/pics/hi32-app-khelpcenter.png
Binary files differ
diff --git a/khelpcenter/pics/hi48-app-khelpcenter.png b/khelpcenter/pics/hi48-app-khelpcenter.png
new file mode 100644
index 00000000..24582cf5
--- /dev/null
+++ b/khelpcenter/pics/hi48-app-khelpcenter.png
Binary files differ
diff --git a/khelpcenter/pics/hi64-app-khelpcenter.png b/khelpcenter/pics/hi64-app-khelpcenter.png
new file mode 100644
index 00000000..6ea007cf
--- /dev/null
+++ b/khelpcenter/pics/hi64-app-khelpcenter.png
Binary files differ
diff --git a/khelpcenter/pics/hisc-app-khelpcenter.svgz b/khelpcenter/pics/hisc-app-khelpcenter.svgz
new file mode 100644
index 00000000..65a9d2dc
--- /dev/null
+++ b/khelpcenter/pics/hisc-app-khelpcenter.svgz
Binary files differ
diff --git a/khelpcenter/plugins/Applications/.directory b/khelpcenter/plugins/Applications/.directory
new file mode 100644
index 00000000..a6602def
--- /dev/null
+++ b/khelpcenter/plugins/Applications/.directory
@@ -0,0 +1,60 @@
+[KDE Desktop Entry]
+
+Name=Application Manuals
+Name[bg]=Ръководства на аплети
+Name[ca]=Manuals de les aplicacions
+Name[cs]=Příručky aplikací
+Name[csb]=Pòdrãczniczi aplikacëjów
+Name[cy]=Llawlyfrau Cymhwysiad
+Name[da]=Programmanualer
+Name[de]=Handbücher zu Programmen
+Name[el]=Εγχειρίδια εφαρμογής
+Name[eo]=Manlibroj de Aplikaĵoj
+Name[es]=Manuales de las aplicaciones
+Name[et]=Rakenduste käsiraamatud
+Name[fo]=Forritshandbøkur
+Name[fr]=Manuels des applications
+Name[hi]=अनुप्रयोग निर्देशिका
+Name[hr]=Priručnici aplikacija
+Name[hu]=Alkalmazások kézikönyvei
+Name[is]=Handbækur forrita
+Name[it]=Manuali applicazione
+Name[ja]=アプリケーションマニュアル
+Name[km]=សៀវភៅ​​កម្មវិធី
+Name[ko]=프로그램 사용 설명서
+Name[lo]=ແອບຟີເຄຊັ້ນ
+Name[lt]=Programų vadovai
+Name[lv]=Programmu rokasgrāmatas
+Name[mn]=Програмын гарын авлага
+Name[mt]=Manwali tal-Programmi
+Name[nb]=Håndbok miniprogrammer
+Name[nds]=Programmhandböker
+Name[nl]=Programmahandboeken
+Name[nn]=Programmanualar
+Name[nso]=Di-Manual tsa Tshomiso
+Name[pl]=Podręczniki programów
+Name[pt]=Manuais das Aplicações
+Name[pt_BR]=Manuais de Aplicativos
+Name[ro]=Manualele aplicațiilor
+Name[ru]=Руководства приложений
+Name[sk]=Aplikačné manuály
+Name[sl]=Priročniki za programe
+Name[sr]=Упутства за програме
+Name[sr@Latn]=Uputstva za programe
+Name[sv]=Programhandböcker
+Name[tg]=Дастури барномаҳо
+Name[th]=คู่มือแอพพลิเคชั่น
+Name[tr]=Uygulama Kılavuzları
+Name[uk]=Підручники програм
+Name[ven]=Apulikhesheni
+Name[wa]=Esplikêyes do programe
+Name[xh]=Isicelo Sesandla
+Name[zh_TW]=應用程式手冊
+Name[zu]=Izincwadi zesandla Zomyaleli
+
+X-DOC-Weight=-500
+
+X-KDE-KHelpcenter-Special=apps
+
+X-DOC-DocumentType=text/docbook
+X-DOC-Identifier=kde_application_manuals
diff --git a/khelpcenter/plugins/Applications/Makefile.am b/khelpcenter/plugins/Applications/Makefile.am
new file mode 100644
index 00000000..2aa425cd
--- /dev/null
+++ b/khelpcenter/plugins/Applications/Makefile.am
@@ -0,0 +1,3 @@
+
+applications_DATA = .directory
+applicationsdir = $(kde_datadir)/khelpcenter/plugins/Applications
diff --git a/khelpcenter/plugins/Makefile.am b/khelpcenter/plugins/Makefile.am
new file mode 100644
index 00000000..3bb2f146
--- /dev/null
+++ b/khelpcenter/plugins/Makefile.am
@@ -0,0 +1,9 @@
+
+SUBDIRS = Applications Manpages Tutorials Scrollkeeper
+
+plugin_DATA = applets.desktop contact.desktop faq.desktop info.desktop \
+ links.desktop support.desktop userguide.desktop welcome.desktop \
+ kicmodules.desktop kcontrolmodules.desktop konqplugins.desktop \
+ kioslaves.desktop
+
+plugindir = $(kde_datadir)/khelpcenter/plugins
diff --git a/khelpcenter/plugins/Manpages/.directory b/khelpcenter/plugins/Manpages/.directory
new file mode 100644
index 00000000..2d4494a9
--- /dev/null
+++ b/khelpcenter/plugins/Manpages/.directory
@@ -0,0 +1,60 @@
+[KDE Desktop Entry]
+Name=UNIX manual pages
+Name[bg]=Ръководство за UNIX
+Name[ca]=Pàgines de manual UNIX
+Name[cs]=Unixové manuálové stránky
+Name[csb]=Starnë manual UNIX-a
+Name[cy]=Tudalennau llawlyfr UNIX
+Name[da]=UNIX manualsider
+Name[de]=UNIX-Handbuchseiten
+Name[el]=Σελίδες man του UNIX
+Name[eo]=Uniksaj Manpaĝoj
+Name[es]=Páginas de manual de Unix
+Name[et]=UNIX-i manuaalileheküljed
+Name[fo]=Unix-handbøkur ("man"-snið)
+Name[fr]=Pages du manuel UNIX
+Name[hi]=यूनिक्स निर्देशिका पृष्ठ
+Name[hr]=UNIX priručnici
+Name[hu]=UNIX man oldalak
+Name[is]=Síður UNIX handbóka
+Name[it]=Pagine manuale UNIX
+Name[ja]=UNIX マニュアルページ
+Name[km]=ទំព័រ​សៀវភៅ​របស់​យូនីក
+Name[ko]=UNIX 매뉴얼 페이지
+Name[lo]=ຊຸດຮູບແບບ KWM
+Name[lt]=UNIX man (programų vadovų) puslapiai
+Name[lv]=UNIX rokasgrāmatas
+Name[mn]=UNIX-Гарын авлага хуудсууд
+Name[mt]=Paġni tal-manwali UNIX
+Name[nb]=Unix manualsider
+Name[nds]=UNIX man-Sieden
+Name[nl]=Unix-handboeken
+Name[nn]=UNIX-manualsider
+Name[nso]=Matlakala a manual wa UNIX
+Name[pl]=Strony podręcznika UNIX-a
+Name[pt]=Páginas de manual do UNIX
+Name[pt_BR]=Páginas de manual do UNIX
+Name[ro]=Pagini de manual UNIX
+Name[ru]=Страницы руководств UNIX
+Name[sk]=UNIX-ové manuálové stránky
+Name[sl]=Strani priročnika za UNIX
+Name[sr]=UNIX упутне стране
+Name[sr@Latn]=UNIX uputne strane
+Name[sv]=Unix manualsidor
+Name[tg]=Дастури UNIX
+Name[th]=หน้าคู่มือ UNIX
+Name[tr]=UNIX kılavuz sayfaları
+Name[uk]=Сторінки довідки UNIX
+Name[ven]=Masiatari a UNIX
+Name[wa]=Pådjes des esplikêyes UNIX
+Name[xh]=UNIX amaphepha esandla
+Name[zh_TW]=UNIX 手冊
+Name[zu]=Amakhasi Ezincwadi zesandla ze-UNIX
+
+DocPath=man:/
+
+Icon=document2
+
+X-DOC-Weight=500
+X-DOC-DocumentType=text/man
+X-DOC-Identifier=manpages
diff --git a/khelpcenter/plugins/Manpages/Makefile.am b/khelpcenter/plugins/Manpages/Makefile.am
new file mode 100644
index 00000000..81e2405d
--- /dev/null
+++ b/khelpcenter/plugins/Manpages/Makefile.am
@@ -0,0 +1,4 @@
+
+ManPages_DATA = .directory man1.desktop man2.desktop man3.desktop man4.desktop \
+ man5.desktop man6.desktop man7.desktop man8.desktop man9.desktop mann.desktop
+ManPagesdir = $(kde_datadir)/khelpcenter/plugins/Manpages
diff --git a/khelpcenter/plugins/Manpages/man1.desktop b/khelpcenter/plugins/Manpages/man1.desktop
new file mode 100644
index 00000000..e4b45a78
--- /dev/null
+++ b/khelpcenter/plugins/Manpages/man1.desktop
@@ -0,0 +1,74 @@
+[Desktop Entry]
+Name=(1) User Commands
+Name[af]=(1) Gebruiker Opdragte
+Name[ar]=(1) أوامر المستخدم
+Name[be]=(1) Каманды карыстальніка
+Name[bg]=(1) Потребителски команди
+Name[br]=(1) Urzhiadoù arveriad
+Name[bs]=(1) Korisničke naredbe
+Name[ca]=(1) Ordres d'usuari
+Name[cs]=(1) Uživatelské příkazy
+Name[csb]=(1) Pòlét brëkòwnika
+Name[cy]=(1) Gorchmynion Defnyddiwr
+Name[da]=(1) Brugerkommandoer
+Name[de]=(1) Benutzerbefehle
+Name[el]=(1) Εντολές χρήστη
+Name[eo]=(1) Uzantokomandoj
+Name[es]=(1) Órdenes de usuario
+Name[et]=(1) Kasutaja käsud
+Name[eu]=(1) Erabiltzailearen komandoak
+Name[fa]=(۱) فرمانهای کاربر
+Name[fi]=(1) Käyttäjän komennot
+Name[fr]=(1) Commandes utilisateur
+Name[fy]=(1) Brûkerskommando's
+Name[ga]=(1) Orduithe Úsáideora
+Name[gl]=(1) Comandos de Usuario
+Name[he]=פקודות משתמש (1)
+Name[hi]=(1) उपयोक्ता कमांड
+Name[hr]=(1) Korisničke naredbe
+Name[hu]=(1) Felhasználói parancsok
+Name[is]=(1) Notandaskipanir
+Name[it]=(1) Comandi utente
+Name[ja]=(1) ユーザコマンド
+Name[ka]=(1) მომხმარებლის ბრძანებები
+Name[kk]=(1) Пайдаланушы командалар
+Name[km]=(1) ពាក្យ​បញ្ជារបស់​អ្នក​ប្រើ
+Name[ko]=(1) 사용자 명령
+Name[lt]=(1) Naudotojo komandos
+Name[lv]=(1) Lietotāja komandas
+Name[mk]=(1) Кориснички команди
+Name[ms]=(1) Arahan Pengguna
+Name[mt]=(1) Kmandi tal-users
+Name[nb]=(1) Brukerkommandoer
+Name[nds]=(1) Brukerbefehlen
+Name[ne]=(१) प्रयोगकर्ता आदेश
+Name[nl]=(1) Gebruikercommando's
+Name[nn]=(1) Brukarkommandoar
+Name[pa]=(੧) ਉਪਭੋਗੀ ਕਮਾਂਡ
+Name[pl]=(1) Polecenia użytkownika
+Name[pt]=(1) Comandos do Utilizador
+Name[pt_BR]=(1) Comandos do Usuário
+Name[ro]=(1) Comenzi utilizator
+Name[ru]=(1) Пользовательские команды
+Name[rw]= (1) Amabwiriza y'Ukoresha
+Name[se]=(1) Geavaheaddjigohččumat
+Name[sk]=(1) Používateľské príkazy
+Name[sl]=(1) Uporabniški ukazi
+Name[sr]=(1) Корисничке наредбе
+Name[sr@Latn]=(1) Korisničke naredbe
+Name[sv]=(1) Användarkommandon
+Name[ta]=(1) பயன்படுத்துபவர் கட்டளைகள்
+Name[te]=(1) యూజర్ ఆదేశాలు
+Name[tg]=(1) Дастури корбар
+Name[th]=(1) คำสั่งของผู้ใช้
+Name[tr]=(1) Kullanıcı Komutları
+Name[tt]=(1) Qullanuçı Boyırığı
+Name[uk]=(1) Команди користувача
+Name[uz]=(1) Foydalanuvchi uchun buyruqlar
+Name[uz@cyrillic]=(1) Фойдаланувчи учун буйруқлар
+Name[vi]=(1) Lệnh của người dùng
+Name[wa]=(1) Comandes d' uzeu
+Name[zh_CN]=(1) 用户命令
+Name[zh_TW]=(1) 使用者命令
+
+DocPath=man:/(1)
diff --git a/khelpcenter/plugins/Manpages/man2.desktop b/khelpcenter/plugins/Manpages/man2.desktop
new file mode 100644
index 00000000..8e1c68ab
--- /dev/null
+++ b/khelpcenter/plugins/Manpages/man2.desktop
@@ -0,0 +1,75 @@
+[Desktop Entry]
+Name=(2) System Calls
+Name[af]=(2) Stelsel Oproepe
+Name[ar]=(2) نداءات النظام
+Name[be]=(2) Сістэмныя выклікі
+Name[bg]=(2) Системни сигнали
+Name[bn]=(2) সিস্টেম কল
+Name[br]=(3) Galvioù reizhiad
+Name[bs]=(2) Sistemski pozivi
+Name[ca]=(2) Crides al sistema
+Name[cs]=(2) Systémová volání
+Name[csb]=(2) Systemòwé fùnkcëje
+Name[cy]=(2) Galwadau Cysawd
+Name[da]=(2) Systemkald
+Name[de]=(2) Systemaufrufe
+Name[el]=(2) Κλήσεις συστήματος
+Name[eo]=(2) Sistemvokoj
+Name[es]=(2) Llamadas de sistema
+Name[et]=(2) Süsteemsed väljakutsed
+Name[eu]=(2) Sistemaren deiak
+Name[fa]=(۲) فراخوانیهای سیستم
+Name[fi]=(2) Järjestelmäkutsut
+Name[fr]=(2) Appels système
+Name[fy]=(2) Systeemoanroppen
+Name[ga]=(2) Glaonna ar an chóras
+Name[gl]=(2) Chamadas do Sistema
+Name[he]=קריאות מערכת (2)
+Name[hi]=(2) सिस्टम काल्स
+Name[hr]=(2) Sistemski pozivi
+Name[hu]=(2) Rendszerhívások
+Name[is]=(2) Kerfisköll
+Name[it]=(2) Chiamate di sistema
+Name[ja]=(2) システムコール
+Name[ka]=(2) სისტემური გამოძახებები
+Name[kk]=(2) Жүйелік шақырулар
+Name[km]=(2) ការ​ហៅ​ប្រព័ន្ធ
+Name[ko]=(2) 시스템 콜
+Name[lt]=(2) Sisteminiai iškvietimai
+Name[lv]=(2) Sistēmas izsaukumi
+Name[mk]=(2) Системски повици
+Name[ms]=(2) Panggilan Sistem
+Name[mt]=(2) Sejħiet tas-sistema
+Name[nb]=(2) Systemkall
+Name[nds]=(2) Systeemoprööp
+Name[ne]=(२) प्रणाली कल
+Name[nl]=(2) Systeemaanroepen
+Name[nn]=(2) Systemkall
+Name[pa]=(੨) ਸਿਸਟਮ ਕਾਲਾਂ
+Name[pl]=(2) Funkcje systemowe
+Name[pt]=(2) Chamadas do Sistema
+Name[pt_BR]=(2) Chamadas de Sistema
+Name[ro]=(2) Apeluri de sistem
+Name[ru]=(2) Системные вызовы
+Name[rw]=(2) Amahamagara Sisitemu
+Name[se]=(2) Vuogádatgohččumat
+Name[sk]=(2) Systémové volania
+Name[sl]=(2) Sistemski klici
+Name[sr]=(2) Системски позиви
+Name[sr@Latn]=(2) Sistemski pozivi
+Name[sv]=(2) Systemanrop
+Name[ta]=(2) கணினி அழைப்புகள்
+Name[te]=(2) వ్యవస్థ కాల్స్
+Name[tg]=(2) Зангҳои система
+Name[th]=(2) คำสั่งของระบบ
+Name[tr]=(2) Sistem Çağrıları
+Name[tt]=(2) Sistem Çaqıruları
+Name[uk]=(2) Системні виклики
+Name[uz]=(2) Tizim chaqiruvlari
+Name[uz@cyrillic]=(2) Тизим чақирувлари
+Name[vi]=(2) Lệnh gọi hệ thống
+Name[wa]=(2) Xhilete do sistinme
+Name[zh_CN]=(2) 系统调用
+Name[zh_TW]=(2) 系統呼叫
+
+DocPath=man:/(2)
diff --git a/khelpcenter/plugins/Manpages/man3.desktop b/khelpcenter/plugins/Manpages/man3.desktop
new file mode 100644
index 00000000..dba88eeb
--- /dev/null
+++ b/khelpcenter/plugins/Manpages/man3.desktop
@@ -0,0 +1,76 @@
+[Desktop Entry]
+Name=(3) Subroutines
+Name[af]=(3) Subroetines
+Name[ar]=(3) الاجراءات الفرعية
+Name[be]=(3) Падпраграмы
+Name[bg]=(3) Подпрограми
+Name[bn]=(3) সাবরুটিন
+Name[br]=(3) Isroudennadoù
+Name[bs]=(3) Podprogrami
+Name[ca]=(3) Subrutines
+Name[cs]=(3) Funkce
+Name[csb]=(3) Pòdprogramë
+Name[cy]=(3) Is-reolweithiau
+Name[da]=(3) Subrutiner
+Name[de]=(3) Funktionsaufrufe
+Name[el]=(3) Υπορουτίνες
+Name[eo]=(3) Subfunkcioj
+Name[es]=(3) Subrutinas
+Name[et]=(3) Alamfunktsioonid
+Name[eu]=(3) Azpi-errutinak
+Name[fa]=(۳) زیرروالها
+Name[fi]=(3) Aliohjelmat
+Name[fr]=(3) Sous-routines
+Name[ga]=(3) Foghnáthaimh
+Name[gl]=(3) Sub-rutinas
+Name[he]=תת־שגרות (3)
+Name[hi]=(3) सबरूटीन्स
+Name[hr]=(3) Pod-rutine
+Name[hu]=(3) Eljárások
+Name[is]=(3) Stefjur
+Name[it]=(3) Sotto procedure
+Name[ja]=(3) サブルーチン
+Name[ka]=(3) პროცედურები
+Name[kk]=(3) Процедуралар
+Name[km]=(3) ទម្រង់ការ​រង
+Name[ko]=(3) 서브루틴
+Name[lo]=ໂດຣເອເທີຍ
+Name[lt]=(3) Paprogramės
+Name[lv]=(3) Subrutīnas
+Name[mk]=(3) Потпрограми
+Name[mn]=(3) Дэд горим
+Name[ms]=(3) Subrutin
+Name[nb]=(3) Delrutiner
+Name[nds]=(3) Funkschonen
+Name[ne]=(३) सबरुटिन
+Name[nn]=(3) Subrutinar
+Name[nso]=(3) Ditsejana
+Name[pa]=(੩) ਸਬ-ਰੂਟੀਨ
+Name[pl]=(3) Podprogramy
+Name[pt]=(3) Sub-rotinas
+Name[pt_BR]=(3) Subrotinas
+Name[ro]=(3) Subrutine
+Name[ru]=(3) Процедуры
+Name[rw]=(3) Ibiceporogaramu
+Name[se]=(3) Vuollerutiinnat
+Name[sk]=(3) Podprogramy
+Name[sl]=(3) Podrutine
+Name[sr]=(3) Подрутине
+Name[sr@Latn]=(3) Podrutine
+Name[sv]=(3) Subrutiner
+Name[ta]=(3)மற்ற நடைமுறைகள்
+Name[te]=(3) సబ్ రొటిన్లు
+Name[tg]=(3) Маросим
+Name[th]=(3) รูทีนย่อย
+Name[tr]=(3) Alt yordamlar
+Name[tt]=(3) Eçprogram
+Name[uk]=(3) Підпрограми
+Name[ven]=(3) Ndila
+Name[vi]=(3) Chương trình con
+Name[wa]=(3) Sorprogrames
+Name[xh]=(3) Ulwenzeko rhoqo olusezantsi
+Name[zh_CN]=(3) 子例程
+Name[zh_TW]=(3) 子程式
+Name[zu]=(3) iqoqo lemisebenzana
+
+DocPath=man:/(3)
diff --git a/khelpcenter/plugins/Manpages/man4.desktop b/khelpcenter/plugins/Manpages/man4.desktop
new file mode 100644
index 00000000..22841b6c
--- /dev/null
+++ b/khelpcenter/plugins/Manpages/man4.desktop
@@ -0,0 +1,81 @@
+[Desktop Entry]
+Name=(4) Devices
+Name[af]=(4) Toestelle
+Name[ar]=(4) الأجهزة
+Name[be]=(4) Прылады
+Name[bg]=(4) Устройства
+Name[bn]=(4) ডিভাইস
+Name[br]=(4) Trobarzhelloù
+Name[bs]=(4) Uređaji
+Name[ca]=(4) Dispositius
+Name[cs]=(4) Zařízení
+Name[csb]=(4) Ùrządzenia
+Name[cy]=(4) Dyfeisiau
+Name[da]=(4) Enheder
+Name[de]=(4) Geräte
+Name[el]=(4) Συσκευές
+Name[eo]=(4) Aparatoj
+Name[es]=(4) Dispositivos
+Name[et]=(4) Seadmed
+Name[eu]=(4) Gailuak
+Name[fa]=(۴) دستگاهها
+Name[fi]=(4) Laitteet
+Name[fr]=(4) Périphériques
+Name[fy]=(4) Apparaten
+Name[ga]=(4) Gléasra
+Name[gl]=(4) Dispositivos
+Name[he]=התקנים (4)
+Name[hi]=(4) औज़ार
+Name[hr]=(4) Uređaji
+Name[hu]=(4) Eszközök
+Name[is]=(4) Tæki
+Name[it]=(4) Dispositivi
+Name[ja]=(4) デバイス
+Name[ka]=(4) მოწყობილობები
+Name[kk]=(4) Құрылғылар
+Name[km]=(4) ឧបករណ៍
+Name[ko]=(4) 장치
+Name[lo]=ອຸປະກອນ
+Name[lt]=(4) Įrenginiai
+Name[lv]=(4) Iekārtas
+Name[mk]=(4) Уреди
+Name[mn]=(4) Төхөөрөмж
+Name[ms]=(4) Peranti
+Name[mt]=(4) Apparat
+Name[nb]=(4) Enheter
+Name[nds]=(4) Reedschappen
+Name[ne]=(४) यन्त्र
+Name[nl]=(4) Apparaten
+Name[nn]=(4) Einingar
+Name[nso]=(4) Maano
+Name[pa]=(੪) ਜੰਤਰ
+Name[pl]=(4) Urządzenia
+Name[pt]=(4) Dispositivos
+Name[pt_BR]=(4) Dispositivos
+Name[ro]=(4) Dispozitive
+Name[ru]=(4) Устройства
+Name[rw]= (4) Amapareye
+Name[se]=(4) Ovttadagat
+Name[sk]=(4) Zariadenia
+Name[sl]=(4) Naprave
+Name[sr]=(4) Уређаји
+Name[sr@Latn]=(4) Uređaji
+Name[sv]=(4) Enheter
+Name[ta]=(4) சாதனங்கள்
+Name[te]=(4) పరికరాలు
+Name[tg]=(4) Дастгоҳҳо
+Name[th]=(4) อุปกรณ์
+Name[tr]=(4) Aygıtlar
+Name[tt]=(4) Cıhazlar
+Name[uk]=(4) Пристрої
+Name[uz]=(4) Uskunalar
+Name[uz@cyrillic]=(4) Ускуналар
+Name[ven]=(4)Maano
+Name[vi]=(4) Thiết bị
+Name[wa]=(4) Éndjins
+Name[xh]=(4) Amacebo
+Name[zh_CN]=(4) 设备
+Name[zh_TW]=(4) 裝置
+Name[zu]=(4) Amathuluzi anenjongo
+
+DocPath=man:/(4)
diff --git a/khelpcenter/plugins/Manpages/man5.desktop b/khelpcenter/plugins/Manpages/man5.desktop
new file mode 100644
index 00000000..8b3fa916
--- /dev/null
+++ b/khelpcenter/plugins/Manpages/man5.desktop
@@ -0,0 +1,81 @@
+[Desktop Entry]
+Name=(5) File Formats
+Name[af]=(5) Lêer Formate
+Name[ar]=(5) هيئات الملفات
+Name[be]=(5) Фарматы файлаў
+Name[bg]=(5) Файлови формати
+Name[bn]=(5) ফাইল ফরম্যাট
+Name[br]=(5) Furmadoù ar restroù
+Name[bs]=(5) Formati datoteka
+Name[ca]=(5) Formats de fitxers
+Name[cs]=(5) Datové formáty
+Name[csb]=(5) Fòrmatë lopków
+Name[cy]=(5) Fformatau Ffeil
+Name[da]=(5) Filformater
+Name[de]=(5) Dateiformate
+Name[el]=(5) Μορφές αρχείων
+Name[eo]=(5) Dosierformatoj
+Name[es]=(5) Formatos de archivo
+Name[et]=(5) Failivormingud
+Name[eu]=(5) Fitxategi formatuak
+Name[fa]=(۵) قالبهای پرونده
+Name[fi]=(5) Tiedostomuodot
+Name[fr]=(5) Formats de fichiers
+Name[fy]=(5) Triemopmaak
+Name[gl]=(5) Formatos de Ficheiro
+Name[he]=תבניות קבצים (5)
+Name[hi]=(5) फ़ाइल फार्मेट्स
+Name[hr]=(5) Oblici datoteka
+Name[hsb]=(5) Datajowe formaty
+Name[hu]=(5) Fájlformátumok
+Name[is]=(5) Skráasnið
+Name[it]=(5) Formato dei file
+Name[ja]=(5) ファイルフォーマット
+Name[ka]=(5) ფაილთა ფორმატები
+Name[kk]=(5) Файл пішімдері
+Name[km]=(5) ទ្រង់ទ្រាយ​ឯកសារ
+Name[ko]=(5) 파일 형식
+Name[lo]=ສູດຄະນິດສາດ - K
+Name[lt]=(5) Bylų formatai
+Name[lv]=(5) Failu formāti
+Name[mk]=(5) Формати на датотеки
+Name[mn]=(5) Файлын хэлбэр
+Name[ms]=(5) Format Fail
+Name[mt]=(5) Formats tal-fajls
+Name[nb]=(5) Filformat
+Name[nds]=(5) Dateiformaten
+Name[ne]=(५) फाइल ढाँचा
+Name[nl]=(5) Bestandsformaten
+Name[nn]=(5) Filformat
+Name[nso]=(5) Dithlolego tsa Faele
+Name[pa]=(੫) ਫਾਇਲ ਫਾਰਮਿਟ
+Name[pl]=(5) Formaty plików
+Name[pt]=(5) Formatos de Ficheiros
+Name[pt_BR]=(5) Formatos de Arquivo
+Name[ro]=(5) Formate de fișiere
+Name[ru]=(5) Форматы файлов
+Name[rw]= (5) Imiterere y'Idosiye
+Name[se]=(5) Fiilaformáhtat
+Name[sk]=(5) Formáty súborov
+Name[sl]=(5) Vrste datotek
+Name[sr]=(5) Формати фајлова
+Name[sr@Latn]=(5) Formati fajlova
+Name[sv]=(5) Filformat
+Name[ta]=(5) கோப்பு வடிவமைப்புகள்
+Name[te]=(5) దస్త్ర ఫార్మెట్లు
+Name[tg]=(5) Намудҳои файл
+Name[th]=(5) รูปแบบแฟ้ม
+Name[tr]=(5) Dosya Biçimleri
+Name[tt]=(5) Birem Töre
+Name[uk]=(5) Формати файлів
+Name[uz]=(5) Fayl formatlari
+Name[uz@cyrillic]=(5) Файл форматлари
+Name[ven]=(5) Tshivhumbeo tsha Faela
+Name[vi]=(5) Định dạng Tập tin
+Name[wa]=(5) Sôres di fitchîs
+Name[xh]=(5) Ifomati Yeefayile
+Name[zh_CN]=(5) 文件格式
+Name[zh_TW]=(5) 檔案格式
+Name[zu]=(5) Izakhiwo zamafayela
+
+DocPath=man:/(5)
diff --git a/khelpcenter/plugins/Manpages/man6.desktop b/khelpcenter/plugins/Manpages/man6.desktop
new file mode 100644
index 00000000..415fe718
--- /dev/null
+++ b/khelpcenter/plugins/Manpages/man6.desktop
@@ -0,0 +1,82 @@
+[Desktop Entry]
+Name=(6) Games
+Name[af]=(6) Speletjies
+Name[ar]=(6) الألعاب
+Name[be]=(6) Гульні
+Name[bg]=(6) Игри
+Name[bn]=(6) খেলা
+Name[br]=(6) C'hoarioù
+Name[bs]=(6) Igre
+Name[ca]=(6) Jocs
+Name[cs]=(6) Hry
+Name[csb]=(6) Grë
+Name[cy]=(6) Gemau
+Name[da]=(6) Spil
+Name[de]=(6) Spiele
+Name[el]=(6) Παιχνίδια
+Name[eo]=(6) Ludoj
+Name[es]=(6) Juegos
+Name[et]=(6) Mängud
+Name[eu]=(6) Jokoak
+Name[fa]=(۶) بازیها
+Name[fi]=(6) Pelit
+Name[fr]=(6) Jeux
+Name[fy]=(6) Spultsjes
+Name[ga]=(6) Cluichí
+Name[gl]=(6) Xogos
+Name[he]=משחקים (6)
+Name[hi]=(6) खेल
+Name[hr]=(6) Igre
+Name[hsb]=(6) Hry
+Name[hu]=(6) Játékok
+Name[is]=(6) Leikir
+Name[it]=(6) Giochi
+Name[ja]=(6) ゲーム
+Name[ka]=(6) თამაშები
+Name[kk]=(6) Ойындар
+Name[km]=(6) ល្បែង
+Name[ko]=(6) 게임
+Name[lo]=ເກມສ์
+Name[lt]=(6) Žaidimai
+Name[lv]=(6) Spēles
+Name[mk]=(6) Игри
+Name[mn]=(6) Тоглоом
+Name[ms]=(6) Permainan
+Name[mt]=(6) Logħob
+Name[nb]=(6) Spill
+Name[nds]=(6) Spelen
+Name[ne]=(६) खेल
+Name[nl]=(6) Spelletjes
+Name[nn]=(6) Spel
+Name[nso]=(6) Dipapadi
+Name[pa]=(੬) ਖੇਡਾਂ
+Name[pl]=(6) Gry
+Name[pt]=(6) Jogos
+Name[pt_BR]=(6) Jogos
+Name[ro]=(6) Jocuri
+Name[ru]=(6) Игры
+Name[rw]= (6) Imikino
+Name[se]=(6) Spealut
+Name[sk]=(6) Hry
+Name[sl]=(6) Igre
+Name[sr]=(6) Игре
+Name[sr@Latn]=(6) Igre
+Name[sv]=(6) Spel
+Name[ta]=(6) விளையாட்டுகள்
+Name[te]=(6) ఆటలు
+Name[tg]=(6) Бозиҳо
+Name[th]=(6) เกม
+Name[tr]=(6) Oyunlar
+Name[tt]=(6) Uyınnar
+Name[uk]=(6) Ігри
+Name[uz]=(6) Oʻyinlar
+Name[uz@cyrillic]=(6) Ўйинлар
+Name[ven]=(6) Mitambo
+Name[vi]=(6) Trò chơi
+Name[wa]=(6) Djeus
+Name[xh]=(6) Imidlalo
+Name[zh_CN]=(6) 游戏
+Name[zh_TW]=(6) 遊戲
+Name[zu]=(6) Imidlalo
+
+DocPath=man:/(6)
diff --git a/khelpcenter/plugins/Manpages/man7.desktop b/khelpcenter/plugins/Manpages/man7.desktop
new file mode 100644
index 00000000..24c6e14e
--- /dev/null
+++ b/khelpcenter/plugins/Manpages/man7.desktop
@@ -0,0 +1,80 @@
+[Desktop Entry]
+Name=(7) Miscellaneous
+Name[af]=(7) Allerlei
+Name[ar]=(7) المتفرقات
+Name[be]=(7) Рознае
+Name[bg]=(7) Разни
+Name[bn]=(7) বিবিধ
+Name[br]=(7) A bep seurt
+Name[bs]=(7) Razno
+Name[ca]=(7) Miscel·lània
+Name[cs]=(7) Různé
+Name[csb]=(7) Wszelejaczé
+Name[cy]=(7) Amrwyiol
+Name[da]=(7) Diverse
+Name[de]=(7) Verschiedenes
+Name[el]=(7) Διάφορα
+Name[eo]=(7) Diversaj
+Name[es]=(7) Varios
+Name[et]=(7) Muud
+Name[eu]=(7) Hainbat
+Name[fa]=(۷) متفرقه
+Name[fi]=(7) Sekalaista
+Name[fr]=(7) Divers
+Name[fy]=(7) Ferskate
+Name[gl]=(7) Miscelánea
+Name[he]=שונות (7)
+Name[hi]=(7) विविध
+Name[hr]=(7) Razno
+Name[hu]=(7) Egyéb
+Name[is]=(7) Ýmislegt
+Name[it]=(7) Varie
+Name[ja]=(7) その他
+Name[ka]=(7) სხვადასხვა
+Name[kk]=(7) Әр түрлі
+Name[km]=(7) ផ្សេងៗ
+Name[ko]=(7) 기타
+Name[lo]=ກູ້ລະເບິດ - K
+Name[lt]=(7) Įvairūs dalykai
+Name[lv]=(7) Dažādi
+Name[mk]=(7) Разно
+Name[mn]=(7) Юм юмнаас
+Name[ms]=(7) Pelbagai
+Name[mt]=(7) Imħalltin
+Name[nb]=(7) Diverse
+Name[nds]=(7) Annerswat
+Name[ne]=(७) विविध
+Name[nl]=(7) Diversen
+Name[nn]=(7) Ymse
+Name[nso]=(7) Hlakahlakanego
+Name[pa]=(੭) ਫੁਟਕਲ
+Name[pl]=(7) Różne
+Name[pt]=(7) Diversos
+Name[pt_BR]=(7) Outros
+Name[ro]=(7) Diverse
+Name[ru]=(7) Разное
+Name[rw]= (7) Binyuranye
+Name[se]=(7) Feará mii
+Name[sk]=(7) Rôzne
+Name[sl]=(7) Razno
+Name[sr]=(7) Разно
+Name[sr@Latn]=(7) Razno
+Name[sv]=(7) Diverse
+Name[ta]=(7) மற்ற
+Name[te]=(7) ఇతర
+Name[tg]=(7) Гуногун
+Name[th]=(7) เบ็ดเตล็ด
+Name[tr]=(7) Çeşitli
+Name[tt]=(7) Başqalar
+Name[uk]=(7) Різне
+Name[uz]=(7) Har xil
+Name[uz@cyrillic]=(7) Ҳар хил
+Name[ven]=(7) Zwisi zwavhudi
+Name[vi]=(7) Linh tinh
+Name[wa]=(7) Totès sôres
+Name[xh]=(7) Ezixubeneyo
+Name[zh_CN]=(7) 杂项
+Name[zh_TW]=(7) 雜項
+Name[zu]=(7) Ingxubevange
+
+DocPath=man:/(7)
diff --git a/khelpcenter/plugins/Manpages/man8.desktop b/khelpcenter/plugins/Manpages/man8.desktop
new file mode 100644
index 00000000..2caad71d
--- /dev/null
+++ b/khelpcenter/plugins/Manpages/man8.desktop
@@ -0,0 +1,79 @@
+[Desktop Entry]
+Name=(8) Sys. Administration
+Name[af]=(8) Sys. Administrasie
+Name[ar]=(8) إدارة النظام
+Name[be]=(8) Сістэмнае адміністраванне
+Name[bg]=(8) Администрация
+Name[bn]=(8) সিস্টেম অ্যাডমিনস্ট্রেশন
+Name[br]=(8) Melestradur ar reizhiad
+Name[bs]=(8) Administracija sistema
+Name[ca]=(8) Administració del sistema
+Name[cs]=(8) Správa systému
+Name[csb]=(8) Sprôwianié systemą
+Name[cy]=(8) Gweinyddiaeth Cysawd
+Name[da]=(8) Systemadministration
+Name[de]=(8) Systemverwaltung
+Name[el]=(8) Διαχείριση συστήματος
+Name[eo]=(8) Sistemadministrado
+Name[es]=(8) Administración del sistema
+Name[et]=(8) Süsteemi administreerimine
+Name[eu]=(8) Sist. kudeaketa
+Name[fa]=(۸) سرپرستی سیستم
+Name[fi]=(8) Järjestelmänhallinta
+Name[fr]=(8) Administration système
+Name[fy]=(8) Systeembehear
+Name[gl]=(8) Administración do Sistema
+Name[he]=ניהול המערכת (8)
+Name[hi]=(8) तंत्र प्रशासन
+Name[hr]=(8) Administracija sustava
+Name[hu]=(8) Rendszeradminisztráció
+Name[is]=(8) Kerfisstjórnun
+Name[it]=(8) Amministrazione di sistema
+Name[ja]=(8) システム管理
+Name[ka]=(8) სისტემური ადმინისტრირება
+Name[kk]=(8) Жүйе әкімшілігі
+Name[km]=(8) ការ​គ្រប់គ្រង​ប្រព័ន្ធ
+Name[ko]=(8) 시스템 관리
+Name[lo]=SAM - ສຳລັບຜູ້ດູແລລະບົບ
+Name[lt]=(8) Sist. administravimas
+Name[lv]=(8) Sistēmas Administrācija
+Name[mk]=(8) Системска администрација
+Name[mn]=(8) Системийн зохион байгуулагч
+Name[ms]=(8) Pentadbiran Sistem
+Name[mt]=(8) Amministrazzjoni tas-sistema
+Name[nb]=(8) Systemadministrasjon
+Name[nds]=(8) Systeempleeg
+Name[ne]=(८) प्रणाली प्रशासन
+Name[nl]=(8) Systeembeheer
+Name[nn]=(8) Systemadministrasjon
+Name[nso]=(8) Bongwaledi bja System
+Name[pa]=(੮) ਸਿਸਟਮ ਪਰਬੰਧਨ
+Name[pl]=(8) Administracja systemu
+Name[pt]=(8) Administração do Sistema
+Name[pt_BR]=(8) Administração do Sistema
+Name[ro]=(8) Administrare de sistem
+Name[ru]=(8) Системное администрирование
+Name[rw]= (8) Iyobora rya Sisitemu
+Name[se]=(8) Vuogádathálddašeapmi
+Name[sk]=(8) Administrácia systému
+Name[sl]=(8) Sistemsko upravljanje
+Name[sr]=(8) Администрација система
+Name[sr@Latn]=(8) Administracija sistema
+Name[sv]=(8) Systemadministration
+Name[ta]=(8) கணினி-நிர்வாகம்
+Name[te]=(8) వ్యవస్థ నిర్వహణ
+Name[tg]=(8) Мудирияти система
+Name[th]=(8) ผู้ดูแลระบบ
+Name[tr]=(8) Sistem Yönetimi
+Name[tt]=(8) Sistem İdäräse
+Name[uk]=(8) Сист. адміністрування
+Name[uz]=(8) Tizimni boshqarish
+Name[uz@cyrillic]=(8) Тизимни бошқариш
+Name[ven]=(8) Ndangulo ya sisitemu
+Name[vi]=(8) Quản trị Hệ thống
+Name[wa]=(8) Manaedjmint do sistinme
+Name[zh_CN]=(8) 系统管理
+Name[zh_TW]=(8) 系統管理
+Name[zu]=(8) Ukugcinwa kwesistimu
+
+DocPath=man:/(8)
diff --git a/khelpcenter/plugins/Manpages/man9.desktop b/khelpcenter/plugins/Manpages/man9.desktop
new file mode 100644
index 00000000..9893a028
--- /dev/null
+++ b/khelpcenter/plugins/Manpages/man9.desktop
@@ -0,0 +1,62 @@
+[Desktop Entry]
+Name=(9) Kernel
+Name[ar]=(9) النواة
+Name[be]=(9) Ядро
+Name[bg]=(9) Ядро
+Name[bn]=(9) কার্নেল
+Name[br]=(9) Kalon
+Name[ca]=(9) Nucli
+Name[cs]=(9) Jádro
+Name[csb]=(9) Jądro systemë
+Name[cy]=(9) Cnewyllen
+Name[da]=(9) Kerne
+Name[el]=(9) Πυρήνας
+Name[eo]=(9) Kerno
+Name[es]=(9) Núcleo
+Name[eu]=(9) Kernela
+Name[fa]=(۹) هسته
+Name[fi]=(9) Ydin
+Name[fr]=(9) Kernel (Noyau)
+Name[ga]=(9) Eithne
+Name[gl]=(9) Núcleo
+Name[he]=גרעין (9)
+Name[hi]=(9) कर्नेल
+Name[is]=(9) Kjarni
+Name[ja]=(9) カーネル
+Name[ka]=(9) ბირთვი
+Name[kk]=(9) Өзегі
+Name[km]=(9) ខឺណែល
+Name[ko]=(9) 커널
+Name[lo]=ເທອຣມີນອລຂອງ X
+Name[lt]=(9) Branduolys
+Name[lv]=(9) Kodols
+Name[mk]=(9) Кернел
+Name[mn]=(9) ҮС-н цөм
+Name[nb]=(9) Kjerne
+Name[nds]=(9) Kernel (Karn vun't Bedriefsysteem)
+Name[ne]=(९) कर्नेल
+Name[nn]=(9) Kjerne
+Name[pa]=(੯) ਕਰਨਲ
+Name[pl]=(9) Jądro systemu
+Name[pt]=(9) 'Kernel'
+Name[ru]=(9) Ядро
+Name[rw]= (9) Intima
+Name[se]=(9) Čoahkku
+Name[sk]=(9) Jadro
+Name[sl]=(9) Jedro
+Name[sr]=(9) Кернел
+Name[sv]=(9) Kärna
+Name[ta]=(9) கெர்னல்
+Name[te]=(9) కెర్నెల్
+Name[tg]=(9) Асосӣ
+Name[th]=(9) เคอร์เนล
+Name[tr]=(9) Çekirdek
+Name[tt]=(9) Töş
+Name[uk]=(9) Ядро
+Name[uz@cyrillic]=(9) Кернел
+Name[vi]=(9) Nhân Linux
+Name[wa]=(9) Fonccions do nawea linux
+Name[zh_CN]=(9) 内核
+Name[zh_TW]=(9) 核心
+
+DocPath=man:/(9)
diff --git a/khelpcenter/plugins/Manpages/mann.desktop b/khelpcenter/plugins/Manpages/mann.desktop
new file mode 100644
index 00000000..75c1e227
--- /dev/null
+++ b/khelpcenter/plugins/Manpages/mann.desktop
@@ -0,0 +1,81 @@
+[Desktop Entry]
+Name=(n) New
+Name[af]=(n) Nuwe
+Name[ar]=(n) جديد
+Name[be]=(n) Новыя
+Name[bg]=(n) Нови
+Name[bn]=(n) নতুন
+Name[br]=(n) Nevez
+Name[bs]=(n) Novo
+Name[ca]=(n) Nou
+Name[cs]=(n) Nové
+Name[csb]=(n) Nowé
+Name[cy]=(n) Newydd
+Name[da]=(n) Ny
+Name[de]=(n) Neu
+Name[el]=(n) Νέο
+Name[eo]=(n) Nova
+Name[es]=(n) Nuevo
+Name[et]=(n) Uus
+Name[eu]=(n) Berria
+Name[fa]=(n) جدید
+Name[fi]=(n) Uudet
+Name[fr]=(n) Nouveautés
+Name[fy]=(n) Nij
+Name[ga]=(n) Nua
+Name[gl]=(n) Novo
+Name[he]=חדש (n)
+Name[hi]=(n) नया
+Name[hr]=(n) Novo
+Name[hu]=(n) Új
+Name[is]=(n) Nýtt
+Name[it]=(n) Nuovi
+Name[ja]=(n) 新規
+Name[ka]=(n) ახალი
+Name[kk]=(n) Жаңа
+Name[km]=(n) ថ្មី
+Name[ko]=(n) 새로운 항목
+Name[lo]=ຂ່າວ - K
+Name[lt]=(n) Nauji dalykai
+Name[lv]=(n) Jauns
+Name[mk]=(n) Нови
+Name[mn]=(n) Шинэ
+Name[ms]=(n) Baru
+Name[mt]=(n) Ġodda
+Name[nb]=(n) Ny
+Name[nds]=(n) Nieg
+Name[ne]=(n) नयाँ
+Name[nl]=(n) Nieuw
+Name[nn]=(n) Ny
+Name[nso]=(n) Ntshwa
+Name[pa]=(n) ਨਵਾਂ
+Name[pl]=(n) nowe
+Name[pt]=(n) Novos
+Name[pt_BR]=(n) Novo
+Name[ro]=(n) Nou
+Name[ru]=(n) Новые
+Name[rw]= (n) Gishya
+Name[se]=(n) Ođđa
+Name[sk]=(n) Nové
+Name[sl]=(n) Novo
+Name[sr]=(n) Ново
+Name[sr@Latn]=(n) Novo
+Name[sv]=(n) Ny
+Name[ta]=(n) புதிய
+Name[te]=(n) కొత్త
+Name[tg]=(n) Нав
+Name[th]=(n) ใหม่
+Name[tr]=(n) Yeni
+Name[tt]=(n) Yaña
+Name[uk]=(n) Нові
+Name[uz]=(n) Yangi
+Name[uz@cyrillic]=(n) Янги
+Name[ven]=(n) Tshiswa
+Name[vi]=(n) Tin tức
+Name[wa]=(n) Novea
+Name[xh]=(n) Entsha
+Name[zh_CN]=(n) 新建
+Name[zh_TW]=(n) 新
+Name[zu]=(n) Okusha
+
+DocPath=man:/(n)
diff --git a/khelpcenter/plugins/Scrollkeeper/.directory b/khelpcenter/plugins/Scrollkeeper/.directory
new file mode 100644
index 00000000..af56360c
--- /dev/null
+++ b/khelpcenter/plugins/Scrollkeeper/.directory
@@ -0,0 +1,9 @@
+[KDE Desktop Entry]
+Name=Scrollkeeper
+Name[eo]=Dokumentara Katalogo
+Name[hi]=स्क्रॉलकीपर
+Name[hr]=Držač klizanja
+Name[km]=ឧបករណ៍​រក្សា​រមូរ
+Name[lo]=ໂປຣແກຣມຮັກສາຈໍພາບ
+Icon=contents2
+X-DOC-Weight=-400
diff --git a/khelpcenter/plugins/Scrollkeeper/Makefile.am b/khelpcenter/plugins/Scrollkeeper/Makefile.am
new file mode 100644
index 00000000..da5dc8f3
--- /dev/null
+++ b/khelpcenter/plugins/Scrollkeeper/Makefile.am
@@ -0,0 +1,3 @@
+
+applications_DATA = .directory scrollkeeper.desktop
+applicationsdir = $(kde_datadir)/khelpcenter/plugins/Scrollkeeper
diff --git a/khelpcenter/plugins/Scrollkeeper/scrollkeeper.desktop b/khelpcenter/plugins/Scrollkeeper/scrollkeeper.desktop
new file mode 100644
index 00000000..990c4703
--- /dev/null
+++ b/khelpcenter/plugins/Scrollkeeper/scrollkeeper.desktop
@@ -0,0 +1,2 @@
+[Desktop Entry]
+X-KDE-KHelpcenter-Special=scrollkeeper
diff --git a/khelpcenter/plugins/Tutorials/.directory b/khelpcenter/plugins/Tutorials/.directory
new file mode 100644
index 00000000..db332034
--- /dev/null
+++ b/khelpcenter/plugins/Tutorials/.directory
@@ -0,0 +1,108 @@
+# KDE Config File
+[KDE Desktop Entry]
+Name=Tutorials
+Name[bg]=Ръководства
+Name[ca]=Programes d'aprenentatge
+Name[cs]=Návody
+Name[csb]=Tutoriale
+Name[cy]=Hyfforddiadau
+Name[da]=Øvelser
+Name[de]=Anleitungen
+Name[el]=Οδηγός χρήσης
+Name[eo]=Eklerniloj
+Name[es]=Tutoriales
+Name[et]=Õppematerjalid
+Name[fo]=Skeið
+Name[fr]=Didactitiels
+Name[hr]=Praktični vodič
+Name[hu]=Bevezetők
+Name[id]=Tutorial
+Name[is]=Kennsluefni
+Name[it]=Esercitazioni
+Name[ja]=チュートリアル
+Name[km]=បង្រៀន
+Name[ko]=따라하기
+Name[lo]=ການສອນ
+Name[lt]=Vadovai
+Name[mn]=Давтлага
+Name[nb]=Veivisere
+Name[nds]=Inföhren
+Name[nl]=Handleidingen
+Name[nn]=Innføringar
+Name[nso]=Dithutokopana
+Name[oc]=Introduccions
+Name[pl]=Podręczniki
+Name[pt]=Tutoriais
+Name[pt_BR]=Tutoriais
+Name[ro]=Tutoriale
+Name[ru]=Обучение
+Name[sk]=Návody
+Name[sl]=Učbeniki
+Name[sr]=Туторијали
+Name[sr@Latn]=Tutorijali
+Name[sv]=Handledningar
+Name[tg]=Дастурҳо
+Name[th]=ฝึกสอน
+Name[tr]=Kılavuzlar
+Name[uk]=Посібники
+Name[ven]=Dzikilasi dzau haseledza
+Name[wa]=Tutoriås
+Name[xh]=Izifundo zokuzikhumbuza
+Name[zh_TW]=教學
+Name[zu]=izifundo zokubuyekeza
+MiniIcon=
+Comment=Tutorial and introduction documents.
+Comment[az]=Leksika və giriş sənədləri
+Comment[bg]=Ръководства и документи.
+Comment[br]=Kelennant ha teulioù deraouiñ.
+Comment[ca]=Curs d'aprenentatge i documents d'introducció.
+Comment[cs]=Návody a základní dokumenty.
+Comment[csb]=Tutorial ë wprowadzającé dokùmentë.
+Comment[cy]=Dogfenni cyflwyniad a hyfforddiadol
+Comment[da]=Øvelses- og introduktionsdokumenter.
+Comment[de]=Anleitungen und Einführungen
+Comment[el]=Οδηγός χρήσης και έγγραφα παρουσίασης.
+Comment[eo]=Eklernilaj kaj enkondukaj dokumentoj
+Comment[es]=Tutorial y documentos de introducción.
+Comment[et]=Õppematerjalid ja sissejuhatused.
+Comment[fr]=Didactitiels et documents de présentation
+Comment[hi]=शिक्षण पाठ तथा परिचय दस्तावेज़
+Comment[hr]=Praktični vodič i uvodni dokumenti.
+Comment[hu]=Bevezető jellegű dokumentumok.
+Comment[id]=Tutorial dan dokumen Pengenalan
+Comment[is]=Kennslu- og kynningarefni.
+Comment[it]=Esercitazione e documenti introduttivi.
+Comment[ja]=チュートリアルと導入用ドキュメント
+Comment[km]=ឯកសារ​បង្រៀន និង​ណែនាំ ។
+Comment[ko]=소개와 따라하기 글입니다.
+Comment[lo]=ການສອນແລະເອກະສານແນະນຳ
+Comment[lt]=Vadovai ir įvadiniai dokumentai
+Comment[lv]=Ievada un konsultāciju dokumenti.
+Comment[mn]=Давтлага ба удиртгал баримтууд
+Comment[mt]=Spjega u dokumenti ta' introduzzjoni.
+Comment[nb]=Veivisere og introduksjonsdokumenter
+Comment[nds]=Anleed- un Inföhrdokmenten
+Comment[nl]=Handleiding en inleidende documenten.
+Comment[nn]=Innføringar og introduksjonsdokument.
+Comment[nso]=Thutokopana le ditokomane tsa matseno.
+Comment[oc]=Documents e curs d'introduccion.
+Comment[pl]=Podręczniki i dokumenty dla początkujących.
+Comment[pt]=Tutoriais e documentos introdutórios.
+Comment[pt_BR]=Tutoriais e documentos introdutórios.
+Comment[ro]=Documente introductive și tutoriale.
+Comment[ru]=Документы по обучению.
+Comment[sk]=Dokumenty s úvodom a návodmi.
+Comment[sl]=Učbenik in uvodni dokumenti
+Comment[sr]=Туторијали и уводни документи.
+Comment[sr@Latn]=Tutorijali i uvodni dokumenti.
+Comment[sv]=Handlednings- och introduktionsdokument.
+Comment[tg]=Дастурҳо ва ҳуҷҷатҳои пешниҳод
+Comment[th]=เอกสารแนะนำและฝึกสอน
+Comment[tr]=Kılavuzlar ve belgeler
+Comment[uk]=Інструктаж і вступні документи.
+Comment[ven]=Kilasi yau haseledza na mathomo a manwalwa
+Comment[wa]=Tutoriå eyet documints di prezintaedje
+Comment[xh]=Isifundo sokuzikhumbuza kunye nesiqalo samaxwebhu.
+Comment[zh_TW]=教學與介紹文件。
+Comment[zu]=Ushicilelo lweziqalo kanye nezifundo zokubuyekeza
+DocPath=
diff --git a/khelpcenter/plugins/Tutorials/Makefile.am b/khelpcenter/plugins/Tutorials/Makefile.am
new file mode 100644
index 00000000..97f85544
--- /dev/null
+++ b/khelpcenter/plugins/Tutorials/Makefile.am
@@ -0,0 +1,5 @@
+
+tut_DATA = .directory quickstart.desktop visualdict.desktop
+tutdir = $(kde_datadir)/khelpcenter/plugins/Tutorials
+
+
diff --git a/khelpcenter/plugins/Tutorials/quickstart.desktop b/khelpcenter/plugins/Tutorials/quickstart.desktop
new file mode 100644
index 00000000..77c9bf95
--- /dev/null
+++ b/khelpcenter/plugins/Tutorials/quickstart.desktop
@@ -0,0 +1,153 @@
+# KDE Config File
+[Desktop Entry]
+Name=Quickstart Guide
+Name[af]=Woerts-warts Gids
+Name[ar]=دليل إرشاد البدء السريع
+Name[az]=Sür'ətli Başlama Rehberi
+Name[be]=Падручнік для пачаткоўца
+Name[bg]=Ръководство за начинаещите
+Name[bn]=কুইকস্টার্ট গাইড
+Name[br]=Sturier Kregiñ fonnus
+Name[bs]=Vodič za brzi početak
+Name[ca]=Guia ràpida
+Name[cs]=Úvodní seznámení
+Name[csb]=Sztartowi prowôdnik
+Name[cy]=Canllaw cychwyn cyflym
+Name[da]=Kvikstart-guide
+Name[de]=Kurzeinführung
+Name[el]=Οδηγός γρήγορου ξεκινήματος
+Name[eo]=Konciza gvidlibro
+Name[es]=Guía rápida
+Name[et]=Kiire sissejuhatus
+Name[eu]=Gida bizkorra
+Name[fa]=راهنمای آغاز سریع
+Name[fi]=Pikaohje
+Name[fr]=Guide de démarrage rapide
+Name[fy]=Fluchstartgids
+Name[gl]=Guia de Início Rápido
+Name[he]=מדריך התחלה מהירה
+Name[hi]=शीघ्रप्रारंभ मार्गदर्शक
+Name[hr]=Brzi uvod
+Name[hu]=Rövid bevezetés
+Name[id]=Petunjuk Memulai Secara Cepat
+Name[is]=Skyndileiðbeiningar
+Name[it]=Guida rapida
+Name[ja]=クイックスタート
+Name[ka]=სახელმძღვანელო დამწყებთათვის
+Name[kk]=Бастаушы бағыттамасы
+Name[km]=មគ្គុទ្ទេសក៍​ចាប់ផ្ដើម​រហ័ស
+Name[ko]=빠른 시작 설명서
+Name[lo]=ຄຳແນະນຳແບບໄວ
+Name[lt]=Greitos pradžios gidas
+Name[lv]=Ātras sākšanas ceļvedis
+Name[mk]=Водич за брзо снаоѓање
+Name[mn]=QuickStart-Зааварчилгаа
+Name[ms]=Panduan Mula Pantas
+Name[mt]=Gwida biex tibda malajr
+Name[nb]=Hurtigstart-guide
+Name[nds]=Fixstart-Föhrer
+Name[ne]=द्रुत सुरुआत मार्गदर्शन
+Name[nl]=Snelstartgids
+Name[nn]=Snøggstarguide
+Name[nso]=Keletso ya Thomiso ya Kapejana
+Name[oc]=Guia rapida
+Name[pa]=ਚੁਸਤ ਸ਼ੁਰੂਆਤ ਗਾਈਡ
+Name[pl]=Przewodnik startowy
+Name[pt]=Guia de Iniciação
+Name[pt_BR]=Guia Rápido
+Name[ro]=Ghid rapid
+Name[ru]=Руководство для начинающих в KDE
+Name[rw]=Iyobora GutangiraVuba
+Name[se]=Oanehis KDE-introdukšuvdna
+Name[sk]=Návod na rýchle použitie
+Name[sl]=Vodnik za hitri začetek
+Name[sr]=Почетни водич
+Name[sr@Latn]=Početni vodič
+Name[sv]=Snabbstartsguide
+Name[ta]=விரைவுதுவக்க வழிகாட்டி.
+Name[tg]=Роҳнамоии шурӯъ кунӣ
+Name[th]=คำแนะนำด่วน
+Name[tr]=Hızlı Başlama Rehberi
+Name[tt]=Tizcibärü Qullanması
+Name[uk]=Посібник для швидкого старту
+Name[uz]=KDE boʻyicha yoʻlkoʻrsatgich
+Name[uz@cyrillic]=KDE бўйича йўлкўрсатгич
+Name[ven]=Tsumbavhulwo ya mathomele au tavhanya
+Name[vi]=Hướng dẫn nhanh
+Name[wa]=Guide d' enondaedje al vole
+Name[xh]=Isikhombisi Sesiqalo esikhawulezayo
+Name[zh_CN]=速成指南
+Name[zh_TW]=快速入門指南
+Name[zu]=Umbonisi wokuqala ngokushesha
+Comment=KDE quickstart guide.
+Comment[af]=KDE woerts-warts gids.
+Comment[ar]=دليل KDE السريع للمبتدئين
+Comment[be]=Падручнік для пачаткоўца KDE.
+Comment[bg]=Кратко ръководство за начинаещи за KDE.
+Comment[bn]=কে.ডি.ই. কুইকস্টার্ট গাইড
+Comment[bs]=KDE kratki vodič.
+Comment[ca]=Guia ràpida del KDE.
+Comment[cs]=Úvodní seznámení s vlastnostmi KDE.
+Comment[csb]=Chùtczi prowôdnik pò KDE.
+Comment[cy]=Canllaw cychwyn cyflym KDE
+Comment[da]=KDE Kvikstart-guide
+Comment[de]=Kurzeinführung in KDE
+Comment[el]=Οδηγός γρήγορου ξεκινήματος KDE.
+Comment[eo]=konciza gvidlibro por KDE
+Comment[es]=Guía de inicio rápido de KDE.
+Comment[et]=Kiire sissejuhatus KDE-sse
+Comment[eu]=KDEren abiatze bizkorreko gida
+Comment[fa]=راهنمای آغاز سریع KDE.
+Comment[fi]=KDE:n aloitusopas.
+Comment[fr]=Guide de démarrage rapide de KDE.
+Comment[fy]=KDE's fluchstartgids.
+Comment[gl]=Guia para iniciar-se axiña en KDE.
+Comment[he]=מדריך התחלה מהירה של KDE.
+Comment[hi]=केडीई शीघ्र मार्गदर्शक
+Comment[hr]=Brzi uvod u KDE.
+Comment[hu]=Rövid bevezetés a KDE-be
+Comment[is]=Skyndileiðbeiningar fyrir KDE.
+Comment[it]=Guida rapida per iniziare di KDE
+Comment[ja]=KDE クイックスタートガイド
+Comment[ka]=KDE-ს სახელმძღვანელო დამწყებთათვის
+Comment[kk]=KDE бастаушының бағыттамасы.
+Comment[km]=មគ្គុទ្ទេសក៍​ចាប់ផ្ដើម​រហ័ស KDE ។
+Comment[ko]=KDE 빠른 시작 설명서입니다.
+Comment[lt]=KDE greitos pradžios gidas.
+Comment[lv]=KDE ātras sākšanas rokasgrāmata.
+Comment[mk]=KDE Водич за брзо снаоѓање
+Comment[mn]=КДЭ-Удиртгал.
+Comment[ms]=Panduan mula pantas KDE.
+Comment[mt]=Gwida tal-KDE biex tibda malajr
+Comment[nb]=Hurtigstart-guide for KDE.
+Comment[nds]=Fixe Inföhren na KDE.
+Comment[ne]=KDE द्रुत सुरुआत मार्गदर्शनड
+Comment[nl]=KDE's snelstartgids.
+Comment[nn]=Snøggstartguide for KDE.
+Comment[pa]=KDE ਚੁਸਤ ਸ਼ੁਰੂਆਤ ਗਾਈਡ ਹੈ।
+Comment[pl]=Szybkie wprowadzenie do KDE.
+Comment[pt]=Guia de introdução ao uso do KDE.
+Comment[pt_BR]=Guia rápido do KDE.
+Comment[ro]=Ghidul rapid pentru KDE.
+Comment[ru]=Руководство для начинающих в KDE
+Comment[rw]=Inyobora gutangiravuba KDE
+Comment[se]=Oanehis KDE-introdukšuvdna
+Comment[sk]=Stručný úvod do KDE.
+Comment[sl]=Vodnik za hitri zagon KDE
+Comment[sr]=KDE-ов почетни водич.
+Comment[sr@Latn]=KDE-ov početni vodič.
+Comment[sv]=KDE:s snabbstartsguide
+Comment[ta]=KDE விரைவுதுவக்க வழிகாட்டி.
+Comment[tg]=Роҳнамоӣ барои навшогирдҳои KDE
+Comment[th]=คำแนะนำด่วนของ KDE
+Comment[tr]=KDE hızlı başlama rehberi.
+Comment[tt]=KDE tiz kereşü qullanması.
+Comment[uk]=Посібник KDE для швидкого старту.
+Comment[uz]=Oʻrganuvchilar uchun KDE boʻyicha yoʻlkoʻrsatgich.
+Comment[uz@cyrillic]=Ўрганувчилар учун KDE бўйича йўлкўрсатгич.
+Comment[vi]=Hướng dẫn nhanh cho KDE
+Comment[wa]=Guide d' enondaedje al vole po KDE
+Comment[zh_CN]=KDE 速成指南。
+Comment[zh_TW]=KDE 快速入門指南。
+Icon=helpdoc
+DocPath=help:/khelpcenter/quickstart/index.html
diff --git a/khelpcenter/plugins/Tutorials/visualdict.desktop b/khelpcenter/plugins/Tutorials/visualdict.desktop
new file mode 100644
index 00000000..ba598a84
--- /dev/null
+++ b/khelpcenter/plugins/Tutorials/visualdict.desktop
@@ -0,0 +1,155 @@
+# KDE Config File
+[Desktop Entry]
+Name=A Visual Guide to KDE
+Name[af]='n Visuele Gids tot KDE
+Name[ar]=مرشد مرئي لِــ KDE
+Name[az]=KDE Üçün Vəzual Bədəçi
+Name[be]=Падручнік KDE па візуальных аб'ектах
+Name[bg]=Нагледни пособия
+Name[bn]=কে.ডি.ই-র জন্য একটি ভিসুয়াল গাইড
+Name[bs]=Vizualni vodič u KDE
+Name[ca]=Una guia visual per al KDE
+Name[cs]=Názorný průvodce prostředím KDE
+Name[csb]=Prowôdnik pò KDE
+Name[cy]=Canllaw Gweledol i KDE
+Name[da]=En visuel guide til KDE
+Name[de]=Visuelle Einführung in KDE
+Name[el]=Ένας οπτικός οδηγός για το KDE
+Name[eo]=Gvidilo pri KDE
+Name[es]=Guía visual de KDE
+Name[et]=KDE visuaalne juhend
+Name[eu]=KDErako gida bisuala
+Name[fa]=یک راهنمای مرئی برای KDE
+Name[fi]=Kuvallinen ohje KDE:hen
+Name[fr]=Un guide visuel de KDE
+Name[fy]=In fisuele KDE-gids
+Name[gl]=Unha Guia Visual de KDE
+Name[he]=מדריך חזותי ל־KDE
+Name[hi]=केडीई के लिए एक दृश्य मार्गदर्शक
+Name[hr]=Vizualni vodič u KDE
+Name[hu]=A KDE grafikus elemeinek ismertetése
+Name[id]=Petunjuk KDE Visual
+Name[is]=Myndrænn leiðarvísir að KDE
+Name[it]=Una guida visiva di KDE
+Name[ja]=KDE のためのビジュアルガイド
+Name[ka]=KDE-ს თვალსაჩინო სახელმძღვანელო
+Name[kk]=KDE көрнекті бағыттамасы
+Name[km]=មគ្គុទ្ទេសក៍​រូបភាព​មក​កាន់ KDE
+Name[ko]=KDE 모습 둘러보기
+Name[lo]=ນຳທ່ງວ KDE ແບບສະເຫມື່ອນแบบเสมือน
+Name[lt]=Vaizdinis KDE gidas
+Name[lv]=Vizuāls Ceļvedis pa KDE
+Name[mk]=Визуелен вовед во KDE
+Name[mn]=КДЭ-н визуал удиртгал
+Name[ms]=Panduan Visual KDE
+Name[mt]=Gwida Viżwali għall-KDE
+Name[nb]=En visuell guide til KDE
+Name[nds]=En visuell Inföhren na KDE
+Name[ne]=KDE मा दृश्य मार्गदर्शन
+Name[nl]=Een visuele KDE-gids
+Name[nn]=Visuell KDE-gaid
+Name[nso]=Keletso yeo e Kwagalago ya KDE
+Name[pa]=KDE ਲਈ ਇੱਕ ਦਿੱਖ ਗਾਈਡ
+Name[pl]=Przewodnik po KDE
+Name[pt]=Um Guia Visual para o KDE
+Name[pt_BR]=Guia Visual para o KDE
+Name[ro]=Ghid vizual KDE
+Name[ru]=Наглядное пособие по KDE
+Name[rw]=Inyobora Igaragara kuri KDE
+Name[se]=Visuella KDE-introdukšuvdna
+Name[sk]=Obrázková príručka KDE
+Name[sl]=Vodnik po KDE
+Name[sr]=Визуелни водич за KDE
+Name[sr@Latn]=Vizuelni vodič za KDE
+Name[sv]=Visuell guide till KDE
+Name[ta]=KDEன் காட்டிசார் வழிகாட்டி
+Name[tg]=Роҳнамои басрии KDE
+Name[th]=นำเที่ยว KDE
+Name[tr]=KDE İçin Görsel Kılavuz
+Name[tt]=KDE öçen Kürsätü-Qullanma
+Name[uk]=Наочний підручник по KDE
+Name[ven]=Tsumbavhulwo ya zwauvhona ya KDE
+Name[vi]=Trình Hướng dẫn Sinh động cho KDE
+Name[wa]=On guide a vey po KDE
+Name[xh]=Isikhombisi esibonakalayo se KDE
+Name[zh_CN]=KDE 可视化指南
+Name[zh_TW]=KDE 視覺指南
+Name[zu]=Umbonisi obonakalayo oya kwi-KDE
+Comment=Guide to KDE widgets
+Comment[af]=Gids na KDE widgets
+Comment[az]=KDE mühitinə sür'ətli başlanğıc
+Comment[be]=Падручнік па віджэтах KDE
+Comment[bg]=Нагледни пособия за KDE, графични елементи, управление и пр.
+Comment[bn]=কে.ডি.ই উইজেট সম্বন্ধে জানুন
+Comment[bs]=Priručnik za KDE ukrase
+Comment[ca]=Guia per als estris a KDE
+Comment[cs]=Průvodce prvky uživatelského prostředí KDE
+Comment[csb]=Prowôdnik pò elementach òknów KDE
+Comment[cy]=Canllaw i declynnau KDE
+Comment[da]=Guide til KDE-kontroller
+Comment[de]=Einführung in die KDE-Elemente
+Comment[el]=Οδηγός για τα γραφικά συστατικά του KDE
+Comment[eo]=Gvidilo pri KDE-fenestraĵoj
+Comment[es]=Guía de los objetos visuales (widgets) de KDE
+Comment[et]=KDE elementide juhend
+Comment[eu]=KDEren widget-en gida
+Comment[fa]=راهنما برای عناصر KDE
+Comment[fi]=Ohje KDE:n työkaluihin
+Comment[fr]=Guide des éléments graphiques de KDE
+Comment[fy]=Gids foar KDE-widgets
+Comment[gl]=Guia dos widgets de KDE
+Comment[he]=מדריך לפריטי KDE
+Comment[hi]=केडीई विजेट्स के लिए एक मार्गदर्शक
+Comment[hr]=Uvod u KDE widgete
+Comment[hu]=A KDE grafikai elemeinek ismertetése
+Comment[id]=Petunjuk widgets KDE
+Comment[is]=Leiðarvísir að viðmótshlutum KDE
+Comment[it]=Guida agli elementi grafici di KDE
+Comment[ja]=KDE ウィジェットガイド
+Comment[ka]=KDE-ს მართვის ელემენტთა სახელმძღვანელო
+Comment[kk]=KDE элементтер бағыттамасы
+Comment[km]=មគ្គុទ្ទេសក៍​វត្ថុ​មើលឃើញ​ក្នុង KDE
+Comment[ko]=KDE 위젯 도움말
+Comment[lo]=ແນະນຳສ່ວນປະກອບຂອງ KDE
+Comment[lt]=KDE valdiklių gidas
+Comment[lv]=Rokasgrāmata KDE vidžetos
+Comment[mk]=Вовед во графичките контроли на KDE
+Comment[mn]=КДЭ-Элементүүдийн удиртгал
+Comment[ms]=Panduan widget KDE
+Comment[mt]=Gwida għall-widgets tal-KDE
+Comment[nb]=Guide til KDEs skjermelementer
+Comment[nds]=Inföhren för KDE-Bedeenelementen
+Comment[ne]=KDE विजेटमा मार्गदर्शन
+Comment[nl]=Gids voor KDE-widgets
+Comment[nn]=Gaid til skjermelementa i KDE
+Comment[nso]=Keletso go di-widget tsa KDE
+Comment[pa]=KDE ਝਰੋਖਿਆਂ ਲਈ ਗਾਈਡ ਹੈ
+Comment[pl]=Przewodnik po elementach okien KDE
+Comment[pt]=Guia para os itens gráficos do KDE
+Comment[pt_BR]=Guia para os controles do KDE
+Comment[ro]=Un ghid pentru componentele grafice ale KDE
+Comment[ru]=Руководство по элементам интерфейса KDE
+Comment[rw]=Kuyobora ku marenga KDE
+Comment[se]=Introdukšuvdna KDE-ađaide
+Comment[sk]=Príručka grafických prvkov KDE
+Comment[sl]=Vodnik po gradnikih KDE
+Comment[sr]=Водич за KDE контроле
+Comment[sr@Latn]=Vodič za KDE kontrole
+Comment[sv]=Guide till KDE-komponenter
+Comment[ta]=KDE வளைவுகளுக்கான வழிகாட்டி
+Comment[tg]=Роҳбарӣ бо ҷузъи робитаи KDE
+Comment[th]=แนะนำวิดเจ็ตของ KDE
+Comment[tr]=KDE Aletleri için rehber
+Comment[tt]=KDE yözarası öçen qullanma
+Comment[uk]=Підручник по віджетам KDE
+Comment[uz]=KDE vidjetlari boʻyicha yoʻlkoʻrsatgich
+Comment[uz@cyrillic]=KDE виджетлари бўйича йўлкўрсатгич
+Comment[ven]=Tsumbavhulwo ya widget ya KDE
+Comment[vi]=Hướng dẫn cho thành tố điều khiển của KDE
+Comment[wa]=Guide po les ahesses di KDE
+Comment[xh]=Isikhombisi esiya kwi KDE widgets
+Comment[zh_CN]=KDE 部件指南
+Comment[zh_TW]=KDE 視窗元件 (widget) 指南
+Comment[zu]=Umbonisi oya kuma-widget e-KDE
+Icon=helpdoc
+DocPath=help:/khelpcenter/visualdict/index.html
diff --git a/khelpcenter/plugins/applets.desktop b/khelpcenter/plugins/applets.desktop
new file mode 100644
index 00000000..646d01e6
--- /dev/null
+++ b/khelpcenter/plugins/applets.desktop
@@ -0,0 +1,85 @@
+[Desktop Entry]
+
+Name=Applet Manuals
+Name[af]=Miniprogram Handleidings
+Name[ar]=كتيّبات إستخدام البريمجات
+Name[be]=Даведкі аплетаў
+Name[bg]=Ръководства на аплети
+Name[bn]=অ্যাপলেট ম্যানুয়াল
+Name[br]=Levr-dorn an arloadig
+Name[bs]=Priručnici appleta
+Name[ca]=Manuals dels applet
+Name[cs]=Příručky appletů
+Name[csb]=Pòdrãczniczi programików
+Name[cy]=Llawlyfr Rhaglennig
+Name[da]=Panelprogrammanualer
+Name[de]=Handbücher zu Miniprogrammen (Applets)
+Name[el]=Εγχειρίδια μικροεφαρμογών
+Name[eo]=Manlibroj de Aplikaĵoj
+Name[es]=Manuales de las miniaplicaciones
+Name[et]=Aplettide käsiraamatud
+Name[eu]=Appleten eskuliburuak
+Name[fa]=پیمانه‌های برنامک
+Name[fi]=Sovelmien ohjekirjat
+Name[fr]=Manuels des applets
+Name[fy]=Appletshânliedingen
+Name[ga]=Lámhleabhair Fheidhmchláiríní
+Name[gl]=Manuais das Applets
+Name[he]=ספרי הדרכה של יישומונים
+Name[hi]=ऐपलेट निर्देशिका
+Name[hr]=Priručnici apleta
+Name[hu]=A kisalkalmazások kézikönyvei
+Name[is]=Handbækur smáforrita
+Name[it]=Manuali applet
+Name[ja]=アプレットマニュアル
+Name[ka]=აპლეტთა სახელმძღვანელო
+Name[kk]=Апплет оқулығы
+Name[km]=សៀវភៅ​អាប់ភ្លេត
+Name[ko]=애플릿 설명서
+Name[lo]=ແອບພີເຄຊັ້ນ
+Name[lt]=Įskiepių vadovai
+Name[lv]=Sīklietotņu rokasgrāmata
+Name[mk]=Прирачници за аплети
+Name[mn]=Гарын авлага (Applets)
+Name[ms]=Manual Aplet
+Name[mt]=Manwali tal-applets
+Name[nb]=Manualer for miniprogrammer
+Name[nds]=Programmhandböker
+Name[ne]=एप्लेट म्यानुअल
+Name[nl]=Applet-handboeken
+Name[nn]=Applet-manualar
+Name[nso]=Di-Manual tsa Applet
+Name[pa]=ਐਪਲਿਟ ਦਸਤਾਵੇਜ਼
+Name[pl]=Podręczniki programików
+Name[pt]=Manuais das 'Applets'
+Name[pt_BR]=Manuais de Mini-aplicativos
+Name[ro]=Manualele miniaplicațiilor
+Name[ru]=Руководства аплетов
+Name[rw]=Igitabomikorere Apuleti
+Name[se]=Prográmmaš-giehtagirjjit
+Name[sk]=Príručky k appletom
+Name[sl]=Priročniki za vstavke
+Name[sr]=Упутства за аплете
+Name[sr@Latn]=Uputstva za aplete
+Name[sv]=Miniprogramhandböcker
+Name[ta]=குறுநிரல் கையேடு
+Name[te]=అప్లెట్ మెన్యువళ్లు
+Name[tg]=Дастномаҳои барнома
+Name[th]=คู่มือแอพเพล็ต
+Name[tr]=Programcık Kılavuzları
+Name[tt]=Applet Qullanmaları
+Name[uk]=Довідки по аплетам
+Name[uz]= Appletlar uchun qoʻllanmalar
+Name[uz@cyrillic]= Апплетлар учун қўлланмалар
+Name[vi]=Hướng dẫn sử dụng Tiểu ứng dụng
+Name[wa]=Esplikêyes des apliketes
+Name[xh]=Applet Zesandla
+Name[zh_CN]=小应用程序手册
+Name[zh_TW]=面板程式手冊
+Name[zu]=Izincwadi zesandla zama-Applet
+
+Icon=contents2
+
+X-DOC-Weight=-400
+
+X-KDE-KHelpcenter-Special=applets
diff --git a/khelpcenter/plugins/contact.desktop b/khelpcenter/plugins/contact.desktop
new file mode 100644
index 00000000..0d80c7cf
--- /dev/null
+++ b/khelpcenter/plugins/contact.desktop
@@ -0,0 +1,83 @@
+[Desktop Entry]
+DocPath=help:/khelpcenter/index.html?anchor=contact
+
+Name=Contact Information
+Name[af]=Kontak Informasie
+Name[ar]=معلومات التراسل
+Name[be]=Кантактная інфармацыя
+Name[bg]=Информация за връзка
+Name[bn]=যোগাযোগ তথ্য
+Name[br]=Titouroù diwar-benn an darempred
+Name[bs]=Kontakt informacije
+Name[ca]=Informació de contacte
+Name[cs]=Kontaktní informace
+Name[csb]=Wëdowiédzô ò łączbie
+Name[cy]=Gwybodaeth Cysylltu
+Name[da]=Kontaktinformation
+Name[de]=Kontaktinformationen
+Name[el]=Πληροφορίες επικοινωνίας
+Name[eo]=Kontaktinformoj
+Name[es]=Información de contacto
+Name[et]=Kontaktinfo
+Name[eu]=Harremanetarako informazioa
+Name[fa]=اطلاعات تماس
+Name[fi]=Yhteystiedot
+Name[fr]=Contacter l'équipe KDE
+Name[fy]=kontaktynformaasje
+Name[ga]=Eolas Teagmhála
+Name[gl]=Información de Contacto
+Name[he]=מידע ליצירת קשר
+Name[hi]=सम्पर्क जानकारी
+Name[hr]=Kontaktni podaci
+Name[hu]=Kapcsolatfelvétel
+Name[is]=Upplýsingar um tengiliði
+Name[it]=Informazioni contatti
+Name[ja]=コンタクト情報
+Name[ka]=საკონტაქტო ინფორმაცია
+Name[kk]=Қатынас мәліметі
+Name[km]=ព័ត៌មាន​ទាក់ទង
+Name[ko]=연락처 정보
+Name[lo]=ຂໍ້ມູນຕ່າງຯ
+Name[lt]=Kontaktai
+Name[lv]=Kontaktu Informācija
+Name[mk]=Контакт информации
+Name[mn]=Холбогдох мэдээлэл
+Name[ms]=Maklumat Hubungan
+Name[mt]=Informazzjoni dwar kuntatti
+Name[nb]=Kontaktinformasjon
+Name[nds]=Kontaktinformatschoon
+Name[ne]=सम्पर्क सूचना
+Name[nl]=Contactinformatie
+Name[nn]=Kontaktinformasjon
+Name[nso]=Tshedimoso ya Kgokagano
+Name[pa]=ਸੰਪਰਕ ਜਾਣਕਾਰੀ
+Name[pl]=Informacje kontaktowe
+Name[pt]=Informações de Contactos
+Name[pt_BR]=Informações de Contato
+Name[ro]=Informații de contact
+Name[ru]=Контактная информация
+Name[rw]=Aho ubarizwa
+Name[se]=Oktavuohtadieđut
+Name[sk]=Informácie o kontaktoch
+Name[sl]=Informacije za stik
+Name[sr]=Информације о контактима
+Name[sr@Latn]=Informacije o kontaktima
+Name[sv]=Kontaktinformation
+Name[ta]=தொடர்பு தகவல்
+Name[tg]=Иттилооти тамос
+Name[th]=ข้อมูลติดต่อ
+Name[tr]=Bağlantı Bilgisi
+Name[tt]=Elemtä Turında
+Name[uk]=Контактна інформація
+Name[uz]=Bogʻlanish uchun maʼlumot
+Name[uz@cyrillic]=Боғланиш учун маълумот
+Name[ven]=Mafhungo nga vhudalo
+Name[vi]=Thông tin Liên lạc
+Name[wa]=Informåcion sol conoxhance
+Name[xh]=Qhagamshelana Nolwazi
+Name[zh_CN]=联系信息
+Name[zh_TW]=聯絡資訊
+Name[zu]=Ulwazi lwabangathinteka
+
+X-DOC-Weight=3000
+
diff --git a/khelpcenter/plugins/faq.desktop b/khelpcenter/plugins/faq.desktop
new file mode 100644
index 00000000..8650262c
--- /dev/null
+++ b/khelpcenter/plugins/faq.desktop
@@ -0,0 +1,80 @@
+[Desktop Entry]
+DocPath=help:/khelpcenter/faq/index.html
+
+Name=The KDE FAQ
+Name[af]=Die Kde Faq
+Name[ar]=أسئلة KDE المتكررة
+Name[be]=FAQ KDE
+Name[bg]=Често задавани въпроси
+Name[bn]=কে.ডি.ই. FAQ
+Name[bs]=KDE FAQ
+Name[ca]=La PMF del KDE
+Name[cs]=Často kladené dotazy KDE
+Name[csb]=KDE FAQ
+Name[cy]=Y FAQ KDE
+Name[da]=KDE OSS
+Name[de]=Häufig gestellte Fragen zu KDE (FAQ)
+Name[el]=Το KDE FAQ
+Name[eo]=La KDE-Oftaj Demandoj
+Name[es]=Las PF de KDE
+Name[et]=KDE korduma kippuvad küsimused
+Name[eu]=KDE FAQa (maiz egiten diren galderak)
+Name[fa]=پرسشهای متداول KDE
+Name[fi]=KDE FAQ
+Name[fr]=La FAQ (questions fréquentes) de KDE
+Name[fy]=Protte foarkommende fragen oer KDE
+Name[ga]=Ceisteanna Coitianta KDE
+Name[gl]=A FAQ de KDE
+Name[he]=שאלות נפוצות על KDE
+Name[hi]=केडीई एफ़एक्यू
+Name[hr]=KDE FAQ
+Name[hu]=KDE FAQ
+Name[is]=KDE Spurt og Svarað (SoS)
+Name[it]=Domande su KDE (FAQ)
+Name[ja]=KDE FAQ
+Name[ka]=KDE: ძირითადი კითხვები
+Name[kk]=KDE сұрақ пен жауаптар
+Name[km]=សំណួរ​ដែល​សួរ​ដដែលៗ​អំពី KDE
+Name[ko]=KDE 자주 묻는 질문
+Name[lt]=KDE D.U.K.(FAQ)
+Name[lv]=KDE BUJ
+Name[mk]=KDE ЧПП
+Name[mn]=КДЭ-с ихэвчилэн асуугддаг асуултууд (FAQ)
+Name[ms]=FAQ KDE
+Name[mt]=Mistoqsijiet komuni tal-KDE
+Name[nb]=Ofte stilte KDE-spørsmål
+Name[nds]=Dat KDE-FAQ
+Name[ne]=KDE FAQ
+Name[nl]=Veel voorkomde vragen over KDE
+Name[nn]=Ofte stilte KDE-spørsmål
+Name[nso]=FAQ ya KDE
+Name[pa]=KDE ਸਵਾਲ-ਜਵਾਬ
+Name[pl]=Często Zadawane Pytania KDE
+Name[pt]=A FAQ do KDE
+Name[pt_BR]=O FAQ do KDE
+Name[ro]=Răspunsuri la întrebări frecvente
+Name[ru]=KDE: вопросы и ответы
+Name[rw]=Ibibazo Bibazwa Cyane bya KDE
+Name[se]=Dávjá jearahuvvon KDE-gažaldagat (KDE-DJG)
+Name[sk]=KDE FAQ
+Name[sl]=Vprašanja in odgovori o KDE
+Name[sr]=Често постављана питања о KDE-у
+Name[sr@Latn]=Često postavljana pitanja o KDE-u
+Name[sv]=Vanliga frågor om KDE
+Name[ta]=KDE FAQ(அடிக்கடி கேட்கப்படும் கேள்விகள்)
+Name[te]=కెడిఈ ఎఫ్ ఏ క్యు
+Name[tg]=KDE: саволҳо ва ҷавобҳо
+Name[th]=คำถามที่ถามบ่อยของ KDE
+Name[tr]=KDE SSS
+Name[tt]=KDE YBSı
+Name[uk]=ЧАП для KDE
+Name[uz]=KDE TSS
+Name[uz@cyrillic]=KDE ТСС
+Name[vi]=Các câu hỏi hay gặp của KDE
+Name[wa]=Li dicåce ås kesses (FAQ) KDE
+Name[xh]=KDE FAQ
+Name[zh_CN]=KDE FAQ
+Name[zh_TW]=KDE 常見問題
+Name[zu]=I-FAQ ye-KDE
+
+X-DOC-Weight=2000
diff --git a/khelpcenter/plugins/info.desktop b/khelpcenter/plugins/info.desktop
new file mode 100644
index 00000000..6634f6e1
--- /dev/null
+++ b/khelpcenter/plugins/info.desktop
@@ -0,0 +1,80 @@
+[Desktop Entry]
+
+Name=Browse Info Pages
+Name[af]=Blaai deur inligting bladsye (Info pages)
+Name[ar]=تصفح صفحات المعلومات
+Name[be]=Праглядзець старонкі info
+Name[bg]=Преглед на страниците Info
+Name[bn]=ইনফো পেজ ব্রাউজ করুন
+Name[br]=Furchal ar pajennoù titouroù
+Name[bs]=Pregled info stranica
+Name[ca]=Fulleja les pàgines Info
+Name[cs]=Prohlížeč info stránek
+Name[csb]=Przezéranié wëdowiédnëch starnów
+Name[cy]=Pori Tudalennau Info
+Name[da]=Gennemse infosider
+Name[de]=Infoseiten durchsehen
+Name[el]=Περιήγηση στις σελίδες info
+Name[eo]=Rigardu info-paĝojn
+Name[es]=Navegar por páginas info
+Name[et]=Infolehekülgede lehitsemine
+Name[eu]=Arakatu info orriak
+Name[fa]=مرور صفحات اطلاعات
+Name[fi]=Selaa info-sivuja
+Name[fr]=Naviguer dans les pages d'information
+Name[fy]=ynfo-siden trochblêdzje
+Name[ga]=Brabhsáil Leathanaigh Eolais
+Name[gl]=Navegar polas páxinas info
+Name[he]=עיון בדפי מידע
+Name[hi]=इन्फो पृष्ठ ब्राउज़ करें
+Name[hr]=Pretraživanje info stranica
+Name[hu]=Info oldalak
+Name[is]=Flakka um upplýsingasíður
+Name[it]=Sfoglia le pagine "info"
+Name[ja]=Info ページの参照
+Name[ka]=ცნობარის დათვალიერება
+Name[kk]=Info парақтары
+Name[km]=រុករក​ទំព័រ​ព័ត៌មាន
+Name[ko]=Info 페이지 탐색
+Name[lt]=Naršyti info puslapius
+Name[lv]=Pārlūkot info lapas
+Name[mk]=Прелистај ги info страниците
+Name[ms]=Layar Halaman Maklumat
+Name[mt]=Dur il-paġni Info
+Name[nb]=Les info-sider
+Name[nds]=Info-Sieden dörkieken
+Name[ne]=सूचना पृष्ठ ब्राउज गर्नुहोस्
+Name[nl]=Info-pagina's doorbladeren
+Name[nn]=Les info-sider
+Name[pa]=ਜਾਣਕਾਰੀ ਸਫੇ ਝਲਕ
+Name[pl]=Przeglądanie stron informacyjnych
+Name[pt]=Navegar nas Páginas do Info
+Name[pt_BR]=Navegar nas Páginas Info
+Name[ro]=Pagini info
+Name[ru]=Страницы Info
+Name[rw]=Gusura Ipaji y'Amakuru
+Name[se]=Loga info-siidduid
+Name[sk]=Prehliadanie info stránok
+Name[sl]=Brskanje po straneh info
+Name[sr]=Прегледање инфо страница
+Name[sr@Latn]=Pregledanje info stranica
+Name[sv]=Bläddra i info-sidor
+Name[ta]=தகவல் பக்கங்களில் உலாவவும்
+Name[tg]=Саҳифаҳои иттилоотӣ
+Name[th]=เรียกดูหน้าข้อมูล (info)
+Name[tr]=Bilgi Sayfarlarını Tara
+Name[tt]=Info Bitläre
+Name[uk]=Навігація сторінок info
+Name[uz]=Info varaqlarni koʻrish
+Name[uz@cyrillic]=Info варақларни кўриш
+Name[vi]=Duyệt Trang Thông tin
+Name[wa]=Naivyî ezès pådjes d' informåcion
+Name[zh_CN]=浏览信息页面
+Name[zh_TW]=瀏覽資訊頁
+Icon=contents2
+
+X-KDE-KHelpcenter-Special=info
+
+DocPath=info:/dir
+
+X-DOC-Weight=700
diff --git a/khelpcenter/plugins/kcontrolmodules.desktop b/khelpcenter/plugins/kcontrolmodules.desktop
new file mode 100644
index 00000000..414b8a8e
--- /dev/null
+++ b/khelpcenter/plugins/kcontrolmodules.desktop
@@ -0,0 +1,87 @@
+[Desktop Entry]
+
+Name=Control Center Modules
+Name[af]=Beheer Sentrum Modules
+Name[ar]=وحدات مركز التحكم
+Name[be]=Модулі цэнтра кіравання
+Name[bg]=Контролен център
+Name[bn]=নিয়ন্ত্রণ কেন্দ্র মডিউল
+Name[br]=Molladoù ar c'hreizenn ren
+Name[bs]=Moduli kontrolnog centra
+Name[ca]=Mòduls del Centre de control
+Name[cs]=Moduly Ovládacího centra
+Name[csb]=Mòdułë centróm kòntrolë
+Name[cy]=Modiwlau Canolfan Rheoli
+Name[da]=Kontrolcenter-moduler
+Name[de]=Kontrollzentrum-Module
+Name[el]=Αρθρώματα Κέντρου ελέγχου
+Name[en_GB]=Control Centre Modules
+Name[eo]=Stircentraj Moduloj
+Name[es]=Módulos del Centro de control
+Name[et]=Juhtimiskeskuse moodulid
+Name[eu]=Kontrol Gunearen moduluak
+Name[fa]=پیمانه‌های مرکز کنترل
+Name[fi]=Ohjauskeskuksen moduulit
+Name[fr]=Modules du Centre de configuration
+Name[fy]=Konfiguraasjemodules
+Name[ga]=Modúil an Lárionad Rialaithe
+Name[gl]=Módulos do Centro de Control
+Name[he]=מודולי מרכז הבקרה
+Name[hi]=नियंत्रण केंद्र मॉड्यूल्स
+Name[hr]=Moduli upravljačkog središta
+Name[hu]=A Vezérlőpult moduljai
+Name[is]=Stjórnborðseiningar
+Name[it]=Moduli del centro di controllo
+Name[ja]=コントロールセンターモジュール
+Name[ka]=მართვის ცენტრის მოდულები
+Name[kk]=Басқару орталық модульдері
+Name[km]=ម៉ូឌុល​មជ្ឈមណ្ឌល​បញ្ជា
+Name[ko]=제어판 모듈
+Name[lo]=ສູນຄວບຄຸມ
+Name[lt]=Valdymo centro moduliai
+Name[lv]=Kontroles centra moduļi
+Name[mk]=Модули од Контролниот Центар
+Name[mn]=Удирдах төв-модул
+Name[ms]=Modul Pusat Kawalan
+Name[mt]=Moduli taċ-Ċentru tal-Kontroll
+Name[nb]=Kontrollpanelmoduler
+Name[nds]=Kuntrullzentrum-Modulen
+Name[ne]=नियन्त्रण केन्द्र मोड्युल
+Name[nl]=Configuratiecentrummodules
+Name[nn]=Kontrollsentermodular
+Name[nso]=Diripa tsa Bogareng bja Taolo
+Name[pa]=ਕੰਟਰੋਲ ਕੇਂਦਰ ਮੈਡੀਊਲ
+Name[pl]=Moduły centrum sterowania
+Name[pt]=Módulos do Centro de Controlo
+Name[pt_BR]=Módulos do Centro de Controle
+Name[ro]=Module Centru de Control
+Name[ru]=Модули Центра управления
+Name[rw]=Kugenzura Ibice byo Hagati
+Name[se]=Stivrenguovddášmoduvllat
+Name[sk]=Moduly Ovládacieho centra
+Name[sl]=Moduli nadzornega središča
+Name[sr]=Модули контролног центра
+Name[sr@Latn]=Moduli kontrolnog centra
+Name[sv]=Moduler i Inställningscentralen
+Name[ta]=கட்டுப்பாட்டு மைய பகுதிகள்
+Name[te]=నియంత్రణా కేంద్రం మాడ్యూళ్లు
+Name[tg]=Бахшҳои маркази идоракунӣ
+Name[th]=โมดูลของศูนย์ควบคุม
+Name[tr]=Kontrol Merkezi Modülleri
+Name[tt]=İdärä Üzägeneñ Modulları
+Name[uk]=Модулі центру керування
+Name[uz]=Boshqaruv markazining modullari
+Name[uz@cyrillic]=Бошқарув марказининг модуллари
+Name[ven]=Modulu wa Senthara ya vhulanguli
+Name[vi]=Trung tâm Điều khiển Mô đun
+Name[wa]=Modules do cinte di contrôle di KDE
+Name[xh]=Izicatshulwa Zolawulo Ezisembindini
+Name[zh_CN]=控制中心模块
+Name[zh_TW]=控制中心模組
+Name[zu]=Izingxenye ze-Control Center
+
+Icon=kcontrol
+
+X-DOC-Weight=-400
+
+X-KDE-KHelpcenter-Special=kcontrol
diff --git a/khelpcenter/plugins/kicmodules.desktop b/khelpcenter/plugins/kicmodules.desktop
new file mode 100644
index 00000000..03af463c
--- /dev/null
+++ b/khelpcenter/plugins/kicmodules.desktop
@@ -0,0 +1,87 @@
+[Desktop Entry]
+
+Name=KInfoCenter Modules
+Name[af]=K Inligting Sentrum Modules
+Name[ar]=وحدات مركز المعلومات
+Name[be]=Модулі інфармацыйнага цэнтра
+Name[bg]=Информационен център
+Name[bn]=KInfoCenter মডিউল
+Name[br]=Molladoù KInfoCenter
+Name[bs]=Moduli za KInfoCenter
+Name[ca]=Mòduls del KInfoCenter
+Name[cs]=Moduly Informačního centra
+Name[csb]=Wëdowiédny mòdułë centróm kòntrolë
+Name[cy]=Modiwlau KInfoCenter
+Name[da]=KInfoCenter-moduler
+Name[de]=Infozentrum-Module
+Name[el]=Αρθρώματα KInfoCenter
+Name[en_GB]=KInfoCentre Modules
+Name[eo]=Infocentraj moduloj
+Name[es]=Módulos del KInfoCenter
+Name[et]=Infokeskuse moodulid
+Name[eu]=KInfoCenter moduluak
+Name[fa]=پیمانه‌های KInfoCenter
+Name[fi]=KInfoCenter-moduulit
+Name[fr]=Modules du Centre d'informations
+Name[fy]=Ynformaasjesintrummodules
+Name[ga]=Modúil KInfoCenter
+Name[gl]=Módulos do Centro de Información de KDE
+Name[he]=מודולי מרכז המידע
+Name[hi]=के-जानकारी-सेंटर मॉड्यूल्स
+Name[hr]=KInfoCenter moduli
+Name[hu]=KInfoCenter-modulok
+Name[is]=Upplýsingaborðseiningar
+Name[it]=Moduli del centro informazioni
+Name[ja]=KInfoCenter モジュール
+Name[ka]=საინფორმაციო ცენტრის მოდულები
+Name[kk]=KInfoCenter модульдері
+Name[km]=ម៉ូឌុល KInfoCenter
+Name[ko]=KInfoCenter 모듈
+Name[lo]=ສູນຄວບຄຸມ
+Name[lt]=KInfoCenter moduliai
+Name[lv]=KInfo centra moduļi
+Name[mk]=KInfoCenter модули
+Name[mn]=Мэд төв-модул
+Name[ms]=Modul KInfoCenter
+Name[mt]=Moduli taċ-Ċentru tal-Informazzjoni
+Name[nb]=Infosentermoduler
+Name[nds]=Modulen för dat KDE-Infozentrum
+Name[ne]=केडीई सूचना केन्द्र मोड्युल
+Name[nl]=Informatiecentrummodules
+Name[nn]=Infosentermodular
+Name[nso]=Diripa tsa Bogareng bja Tshedimoso ya K
+Name[pa]=ਕੇਜਾਣਕਾਰੀ ਕੇਂਦਰ ਮੈਡੀਊਲ
+Name[pl]=Moduły informacyjne Centrum sterowania
+Name[pt]=Módulos do KInfoCenter
+Name[pt_BR]=Módulo do Centro de Informações do KDE
+Name[ro]=Module Centru de Informații
+Name[ru]=Модули Центра информации
+Name[rw]=Ibice K-UmwanyaAmakuru
+Name[se]=Diehtoguovddášmoduvllat
+Name[sk]=Moduly pre Informačné centrum
+Name[sl]=Moduli Informacijega središča
+Name[sr]=KInfoCenter модули
+Name[sr@Latn]=KInfoCenter moduli
+Name[sv]=Moduler i Informationscentralen
+Name[ta]=கேதகவல் மைய பகுதிகள்
+Name[te]=కెసమాచార కేంద్రం మాడ్యూళ్లు
+Name[tg]=Бахшҳои маркази иттилоот
+Name[th]=โมดูลของศูนย์ข้อมูล
+Name[tr]=KInfoCenter Modülleri
+Name[tt]=KInfoCenter Öleşläre
+Name[uk]=Модулі KInfoCenter
+Name[uz]=KInfoCenter modullari
+Name[uz@cyrillic]=KInfoCenter модуллари
+Name[ven]=Modulu ya senthara ya mafhungo a K
+Name[vi]=Mô đun Trung tâm Thông tin của KDE
+Name[wa]=Modules do cinte d' informåcion di KDE
+Name[xh]=Izicatshulwa ze KInfoCenter
+Name[zh_CN]=KInfoCenter 模块
+Name[zh_TW]=KInfoCenter 模組
+Name[zu]=Izingxenye ze-KInfoCenter
+
+Icon=contents2
+
+X-DOC-Weight=-400
+
+X-KDE-KHelpcenter-Special=kinfocenter
diff --git a/khelpcenter/plugins/kioslaves.desktop b/khelpcenter/plugins/kioslaves.desktop
new file mode 100644
index 00000000..452ecd50
--- /dev/null
+++ b/khelpcenter/plugins/kioslaves.desktop
@@ -0,0 +1,35 @@
+[Desktop Entry]
+
+Name=Kioslaves
+Name[bg]=Система за вход-изход
+Name[cs]=Pomocné protokoly KDE
+Name[csb]=Pluginsë wéńdzeniô/wińdzeniô
+Name[da]=Kioslaver
+Name[de]=Ein-/Ausgabemodule
+Name[eo]=Kenelservoj
+Name[et]=KIO moodulid
+Name[fi]=KIO-palvelut
+Name[gl]=Escravos Kio
+Name[hi]=केआईओ-स्लेव्स
+Name[hu]=KDE-protokollok
+Name[it]=Kioslave
+Name[ja]=Kioslave
+Name[ko]=KIO 슬레이브
+Name[lt]=Kiovergai
+Name[lv]=KIO vergi
+Name[nb]=Kioslaver
+Name[nds]=In-/Utgaavmodulen
+Name[ne]=किओस्लेभ
+Name[nn]=Kioslavar
+Name[pl]=Wtyczki wejścia/wyjścia
+Name[ro]=Dispozitive KIO
+Name[se]=KIO-šlávat
+Name[sv]=I/O-slavar
+Name[te]=కెఐఒ బానిసలు
+Name[tg]=Бандаҳои Kio
+Name[uk]=Підлеглі В/В
+Icon=contents2
+
+X-DOC-Weight=-400
+
+X-KDE-KHelpcenter-Special=kioslave
diff --git a/khelpcenter/plugins/konqplugins.desktop b/khelpcenter/plugins/konqplugins.desktop
new file mode 100644
index 00000000..6ea4ffe7
--- /dev/null
+++ b/khelpcenter/plugins/konqplugins.desktop
@@ -0,0 +1,85 @@
+[Desktop Entry]
+
+Name=Konqueror Plugins
+Name[af]=Konqueror Inprop modules
+Name[ar]=قوابس Konqueror
+Name[be]=Утулкі Konqueror
+Name[bg]=Приставки за браузъра
+Name[bn]=কনকরার প্লাগ-ইন
+Name[br]=Lugantoù Konqueror
+Name[bs]=Konqueror dodaci
+Name[ca]=Connectors per a Konqueror
+Name[cs]=Moduly Konqueroru
+Name[csb]=Pluginsë Konquerora
+Name[cy]=Ategynnau Konqueror
+Name[da]=Konqueror-plugin
+Name[de]=Konqueror-Plugins
+Name[el]=Πρόσθετα Konqueror
+Name[eo]=Konkerantaj kromaĵoj
+Name[es]=Complementos de Konqueror
+Name[et]=Konquerori pluginad
+Name[eu]=Konquerorren pluginak
+Name[fa]=وصله‌های Konqueror
+Name[fi]=Konqueror-liitännäiset
+Name[fr]=Modules externes de Konqueror
+Name[fy]=Konqueror-plugins
+Name[ga]=Breiseáin Konqueror
+Name[gl]=Plugins de Konqueror
+Name[he]=תוספים של Konqueror
+Name[hi]=कॉन्करर प्लगइन्स
+Name[hr]=Konqueror dodaci
+Name[hu]=Konqueror-bővítőmodulok
+Name[is]=Konqueror íforrit
+Name[it]=Plugin di Konqueror
+Name[ja]=Konqueror プラグイン
+Name[ka]=Konqueror-ის პლაგინები
+Name[kk]=Konqueror модульдері
+Name[km]=កម្មវិធី​ជំនួយ​ខាង​ក្នុង Konqueror
+Name[ko]=Konqueror 창
+Name[lo]=ບາວເຊີ Konqueror
+Name[lt]=Konqueror priedai
+Name[lv]=Iekarotāja spraudņi
+Name[mk]=Приклучоци за Konqueror
+Name[mn]=Конкюрор-плугинс
+Name[ms]=Plugin Konqueror
+Name[mt]=Plagins ta' Konqueror
+Name[nb]=Konqueror-programtillegg
+Name[nds]=Konqueror-Plugins
+Name[ne]=कन्क्वेरर प्लगइन
+Name[nl]=Konqueror-plugins
+Name[nn]=Konqueror-programtillegg
+Name[nso]=Ditsenyo tsa Konqueror
+Name[pa]=ਕੋਨਕਿਉਰਰ ਪਲੱਗਇਨ
+Name[pl]=Wtyczki Konquerora
+Name[pt]='Plugins' do Konqueror
+Name[pt_BR]=Plug-Ins do Konqueror
+Name[ro]=Module Konqueror
+Name[ru]=Модули Konqueror
+Name[rw]=Amacomeka Konqueror
+Name[se]=Konqueror-lassemoduvllat
+Name[sk]=Moduly pre Konqueror
+Name[sl]=Vstavki za Konqueror
+Name[sr]=Konqueror-ови прикључци
+Name[sr@Latn]=Konqueror-ovi priključci
+Name[sv]=Konqueror-insticksprogram
+Name[ta]=கான்கொரர் செருகு சாதனங்கள்
+Name[te]=కాంకెరర్ ప్లగిన్లు
+Name[tg]=Мутассалкунандаҳои Konqueror
+Name[th]=ปลั้กอินของคอนเควอร์เรอร์
+Name[tr]=Konqueror Eklentileri
+Name[tt]=Konqueror Östämäläre
+Name[uk]=Втулки для Konqueror
+Name[uz]=Konqueror plaginlari
+Name[uz@cyrillic]=Konqueror плагинлари
+Name[vi]=Trình bổ sung Konqueror
+Name[wa]=Tchôke-divins po Konqueror
+Name[xh]=Iplagi zangaphakathi ze Konqueror
+Name[zh_CN]=Konqueror 插件
+Name[zh_TW]=Konqueror 外掛程式
+Name[zu]=Ama-Plugin e-Konqueror
+
+Icon=konqueror
+
+X-DOC-Weight=-400
+
+X-KDE-KHelpcenter-Special=konqueror
diff --git a/khelpcenter/plugins/links.desktop b/khelpcenter/plugins/links.desktop
new file mode 100644
index 00000000..b0516802
--- /dev/null
+++ b/khelpcenter/plugins/links.desktop
@@ -0,0 +1,77 @@
+[Desktop Entry]
+DocPath=help:/khelpcenter/index.html?anchor=links
+
+Name=KDE on the Web
+Name[af]=KDE op die Web
+Name[ar]=KDE على الشبكة
+Name[be]=KDE у Сеціве
+Name[bg]=KDE в Интернет
+Name[bn]=ওয়েব-এ কে.ডি.ই.
+Name[br]=KDE war ar Gwiad
+Name[bs]=KDE na webu
+Name[ca]=KDE a la web
+Name[cs]=KDE na webu
+Name[csb]=KDE w sécë
+Name[cy]=KDE ar y We
+Name[da]=KDE på nettet
+Name[de]=KDE im Web
+Name[el]=Το KDE στο διαδίκτυο
+Name[eo]=KDE en TTT
+Name[es]=KDE en la web
+Name[et]=KDE veebis
+Name[eu]=KDE Web-ean
+Name[fa]=KDE روی وب
+Name[fi]=KDE webissä
+Name[fr]=KDE sur le web
+Name[fy]=KDE op it ynternet
+Name[ga]=KDE ar an Ghréasán
+Name[gl]=KDE na web
+Name[he]=KDE באינטרנט
+Name[hi]=केडीई वेब पर
+Name[hr]=KDE na Internetu
+Name[hu]=A KDE az interneten
+Name[is]=KDE á vefnum
+Name[it]=KDE su internet
+Name[ja]=ウェブ上の KDE
+Name[ka]=KDE ინტერნეტში
+Name[kk]=KDE Интернетте
+Name[km]=KDE លើ​បណ្ដាញ
+Name[ko]=웹에서의 KDE
+Name[lt]=KDE žiniatinklyje
+Name[lv]=KDE tīklā
+Name[mk]=KDE на мрежа
+Name[ms]=KDE dalam Web
+Name[mt]=KDE fuq il-Web
+Name[nb]=KDE på nettet
+Name[nds]=KDE in't Nett
+Name[ne]=वेबमा केडीई
+Name[nl]=KDE op het internet
+Name[nn]=KDE på verdsveven
+Name[pa]=ਵੈੱਬ 'ਤੇ KDE
+Name[pl]=KDE w sieci
+Name[pt]=O KDE na Web
+Name[pt_BR]=KDE na Web
+Name[ro]=KDE pe Internet
+Name[ru]=KDE в Интернете
+Name[rw]=KDE ku Rubugamakuru
+Name[se]=KDE interneahtas
+Name[sk]=KDE na WWW
+Name[sl]=KDE na spletu
+Name[sr]=KDE на вебу
+Name[sr@Latn]=KDE na vebu
+Name[sv]=KDE på Internet
+Name[ta]=வலையத்தில் கேடியி
+Name[te]=వెబ్ లొ కెడిఈ
+Name[tg]=KDE дар Интернет
+Name[th]=KDE บนเว็บ
+Name[tr]=Web'de KDE
+Name[tt]=KDE Päräwezdä
+Name[uk]=KDE в Тенетах
+Name[uz]=KDE veb-sahifalari
+Name[uz@cyrillic]=KDE веб-саҳифалари
+Name[vi]=KDE trên mạng
+Name[wa]=KDE sol waibe
+Name[zh_CN]=网上 KDE
+Name[zh_TW]=KDE 網站
+
+X-DOC-Weight=4000
diff --git a/khelpcenter/plugins/support.desktop b/khelpcenter/plugins/support.desktop
new file mode 100644
index 00000000..740e2247
--- /dev/null
+++ b/khelpcenter/plugins/support.desktop
@@ -0,0 +1,83 @@
+[Desktop Entry]
+DocPath=help:/khelpcenter/index.html?anchor=support
+
+Name=Supporting KDE
+Name[af]=Ondersteun KDE
+Name[ar]=دعم KDE
+Name[be]=Падтрымка KDE
+Name[bg]=Подпомагане на KDE
+Name[bn]=কে.ডি.ই-কে সহায়তা
+Name[br]=Skoazellañ KDE
+Name[bs]=Podržite KDE
+Name[ca]=Com col·laborar amb el KDE
+Name[cs]=Podpora KDE
+Name[csb]=Wspiarcë dlô KDE
+Name[cy]=Cefnogi KDE
+Name[da]=Støt KDE
+Name[de]=KDE unterstützen
+Name[el]=Υποστήριξη στο KDE
+Name[eo]=Subteni KDEon
+Name[es]=Colaborando con KDE
+Name[et]=KDE toetamine
+Name[eu]=KDEri lagunduz
+Name[fa]=پشتیبانی KDE
+Name[fi]=KDE:n tukeminen
+Name[fr]=Aider KDE
+Name[fy]=KDE stypje
+Name[ga]=Ag Tacú le KDE
+Name[gl]=Dar Apoio a KDE
+Name[he]=תמיכה ב־KDE
+Name[hi]=केडीई को आधार दें
+Name[hr]=Podrška KDE-u
+Name[hu]=A KDE támogatása
+Name[is]=Styðja KDE
+Name[it]=Aiutare KDE
+Name[ja]=KDE 支援
+Name[ka]=KDE-ს მხარდაჭერა
+Name[kk]=KDE-ні қолдау
+Name[km]=ការ​គាំទ្រ KDE
+Name[ko]=KDE 지원
+Name[lo]=ເກມກີລາ
+Name[lt]=KDE palaikymas
+Name[lv]=KDE atbalstīšana
+Name[mk]=Поддршка за KDE
+Name[mn]=КДЭ дэмжилэг
+Name[ms]=KDE Sokongan
+Name[mt]=Appoġġja lill-KDE
+Name[nb]=Støtt KDE
+Name[nds]=KDE ünnerstütten
+Name[ne]=केडीई समर्थन
+Name[nl]=KDE ondersteunen
+Name[nn]=Støtt KDE
+Name[nso]=Go Thekga KDE
+Name[pa]=KDE ਦੀ ਸਹਾਇਤਾ
+Name[pl]=Wspomaganie KDE
+Name[pt]=Apoiar o KDE
+Name[pt_BR]=Assistência ao KDE
+Name[ro]=Cum să ajutați Proiectul KDE
+Name[ru]=Поддержка KDE
+Name[rw]=Gufasha KDE
+Name[se]=Doarjjo KDE
+Name[sk]=Podpora KDE
+Name[sl]=Podpiranje KDE
+Name[sr]=Подржавање KDE-а
+Name[sr@Latn]=Podržavanje KDE-a
+Name[sv]=Ge KDE ditt stöd
+Name[ta]=KDEஐ ஆதரிக்கிறது
+Name[te]=కెడిఈ కి సహాయంచెయండి
+Name[tg]=Пуштибони KDE
+Name[th]=การสนับสนุน KDE
+Name[tr]=KDE'yi Destekleyin
+Name[tt]=KDE Teräge
+Name[uk]=Підтримка KDE
+Name[uz]=KDE'ni qoʻllab-quvvatlash
+Name[uz@cyrillic]=KDE'ни қўллаб-қувватлаш
+Name[ven]=U tikedza KDE
+Name[vi]=Hỗ trợ KDE
+Name[wa]=Sopoirter KDE
+Name[xh]=Ixhasa i KDE
+Name[zh_CN]=支持 KDE
+Name[zh_TW]=支援 KDE
+Name[zu]=Ixhasa i-KDE
+
+X-DOC-Weight=5000
diff --git a/khelpcenter/plugins/userguide.desktop b/khelpcenter/plugins/userguide.desktop
new file mode 100644
index 00000000..437fc27e
--- /dev/null
+++ b/khelpcenter/plugins/userguide.desktop
@@ -0,0 +1,78 @@
+[Desktop Entry]
+DocPath=help:/khelpcenter/userguide/index.html
+
+Name=KDE Users' Manual
+Name[af]=KDE gebruiker handleiding
+Name[ar]=دليل KDE للمستخدمين
+Name[be]=Падручнік карыстальніка KDE
+Name[bg]=Ръководство за употреба
+Name[bn]=কে.ডি.ই. ব্যবহারকারীদের জন্য ম্যানুয়াল
+Name[br]=Levr-dorn arveriaded KDE
+Name[bs]=KDE korisnički priručnik
+Name[ca]=Manual d'usuari KDE
+Name[cs]=Příručka uživatele KDE
+Name[csb]=Pòdrãcznik brëkòwnika KDE
+Name[cy]=Llawlyfr Defnyddwyr KDE
+Name[da]=KDE-brugervejledning
+Name[de]=KDE-Benutzerhandbuch
+Name[el]=Εγχειρίδιο χρήστη του KDE
+Name[eo]=KDE-uzantula manlibro
+Name[es]=Manual del usuario de KDE
+Name[et]=KDE kasutaja käsiraamat
+Name[eu]=KDEren erabiltzailearen eskuliburua
+Name[fa]=راهنمای کاربران KDE
+Name[fi]=KDE:n käyttöohje
+Name[fr]=Manuel de l'utilisateur de KDE
+Name[fy]=KDE's hânlieding
+Name[ga]=Lámhleabhar KDE d'úsáideoirí
+Name[gl]=Manual de usuario de KDE
+Name[he]=המדריך למשתמש ב־KDE
+Name[hi]=केडीई उपयोक्ता निर्देशिका
+Name[hr]=KDE korisnički priručnik
+Name[hu]=KDE-felhasználók kézikönyve
+Name[is]=KDE notandahandbækur
+Name[it]=Manuale degli utenti di KDE
+Name[ja]=KDE ユーザマニュアル
+Name[ka]=KDE-ს მომხმარებლის სახელმძღვანელო
+Name[kk]=KDE пайдаланушының оқулығы
+Name[km]=សៀវភៅ​ប្រើ KDE
+Name[ko]=KDE 사용자 설명서
+Name[lt]=KDE naudotojo vadovas
+Name[lv]=KDE lietotāja rokasgrāmata
+Name[mk]=KDE кориснички прирачник
+Name[ms]=Manual Pengguna KDE
+Name[mt]=Manwal tal-users ta' KDE
+Name[nb]=Brukerhandbok for KDE
+Name[nds]=KDE-Brukerhandbook
+Name[ne]=KDE प्रयोगकर्ता म्यानुअल
+Name[nl]=KDE's Gebruikershandboek
+Name[nn]=Brukarhandbok for KDE
+Name[pa]=KDE ਉਪਭੋਗੀ ਦਸਤਾਵੇਜ਼
+Name[pl]=Podręcznik użytkownika KDE
+Name[pt]=Manual do Utilizador do KDE
+Name[pt_BR]=Manual do Usuário do KDE
+Name[ro]=Manualul utilizatorului KDE
+Name[ru]=Руководство пользователя KDE
+Name[rw]=KDE Igitabomikorere cy'Ukoresha
+Name[se]=KDE giehtagirji
+Name[sk]=Príručka pre používateľa KDE
+Name[sl]=Uporabniški priročnik KDE
+Name[sr]=KDE-ово упутство за кориснике
+Name[sr@Latn]=KDE-ovo uputstvo za korisnike
+Name[sv]=KDE:s användarhandbok
+Name[ta]=KDE பயனர்களின் கையேடு
+Name[te]=కెడిఈ యూజర్ మెన్యువల్
+Name[tg]=Дастури корбари KDE
+Name[th]=คู่มือผู้ใช้งาน KDE
+Name[tr]=KDE Kullanıcı Klavuzu
+Name[tt]=KDE Qullanması
+Name[uk]=Підручник користувача KDE
+Name[uz]=KDE uchun qoʻllanma
+Name[uz@cyrillic]=KDE учун қўлланма
+Name[vi]=Hướng dẫn sử dụng KDE
+Name[wa]=Esplikêyes po l' uzeu di KDE
+Name[zh_CN]=KDE 用户手册
+Name[zh_TW]=KDE 使用者手冊
+
+X-DOC-Weight=-2000
+
diff --git a/khelpcenter/plugins/welcome.desktop b/khelpcenter/plugins/welcome.desktop
new file mode 100644
index 00000000..ded6d2e4
--- /dev/null
+++ b/khelpcenter/plugins/welcome.desktop
@@ -0,0 +1,83 @@
+[Desktop Entry]
+DocPath=help:/khelpcenter/index.html?anchor=welcome
+
+Name=Welcome to KDE
+Name[af]=Welkom by KDE
+Name[ar]=مرحباً بك إلى KDE
+Name[be]=Сардэчна запрашаем у KDE
+Name[bg]=Добре дошли в KDE
+Name[bn]=কে.ডি.ই.-তে স্বাগতম্
+Name[br]=Degemer e KDE
+Name[bs]=Dobro došli u KDE
+Name[ca]=Benvingut al KDE
+Name[cs]=Uvítání do KDE
+Name[csb]=Witómë w KDE
+Name[cy]=Croeso i KDE
+Name[da]=Velkommen til KDE
+Name[de]=Willkommen bei KDE
+Name[el]=Καλωσορίσατε στο KDE
+Name[eo]=Bonvenon ĉe KDE
+Name[es]=Bienvenido a KDE
+Name[et]=Tere tulemast KDE-sse
+Name[eu]=Ongi etorria KDEra
+Name[fa]=به KDE خوش آمدید
+Name[fi]=Tervetuloa KDE:hen
+Name[fr]=Bienvenue sur KDE
+Name[fy]=Wolkom by KDE
+Name[ga]=Fáilte go KDE
+Name[gl]=Benvido/a a KDE
+Name[he]=ברוכים הבאים אל KDE
+Name[hi]=केडीई में आपका स्वागत है
+Name[hr]=Dobrodošli u KDE
+Name[hu]=Üdvözöljük a KDE-ben!
+Name[is]=Velkomin að KDE
+Name[it]=Benvenuto in KDE
+Name[ja]=KDE へようこそ
+Name[ka]=მოგესალმებათ KDE
+Name[kk]=KDE-ге қош келдіңіз
+Name[km]=ស្វាគមន៍​មក​កាន់ KDE
+Name[ko]=KDE에 오신 것을 환영합니다
+Name[lo]=ພັດທະນາໂປຣແກຣມ
+Name[lt]=Jus sveikina KDE
+Name[lv]=Laipni lūdzu iekš KDE
+Name[mk]=Добредојдовте во KDE
+Name[mn]=КДЭ-д тавтай морил
+Name[ms]=Selamat Datang ke KDE
+Name[mt]=Merħba għal KDE
+Name[nb]=Velkommen til KDE
+Name[nds]=Willkamen bi KDE
+Name[ne]=केडीईमा स्वागत
+Name[nl]=Welkom bij KDE
+Name[nn]=Velkommen til KDE
+Name[nso]=O Amogetswe go KDE
+Name[pa]=KDE ਵਲੋਂ ਜੀ ਆਇਆਂ ਨੂੰ
+Name[pl]=Witamy w KDE
+Name[pt]=Bem-vindo ao KDE
+Name[pt_BR]=Bem-vindo ao KDE
+Name[ro]=Bine ați venit în KDE
+Name[ru]=Добро пожаловать в KDE
+Name[rw]=Urakaza neza kuri KDE
+Name[se]=Bures boahtin KDE:ii
+Name[sk]=Privítanie KDE
+Name[sl]=Dobrodošli v KDE
+Name[sr]=Добродошли у KDE
+Name[sr@Latn]=Dobrodošli u KDE
+Name[sv]=Välkommen till KDE
+Name[ta]=KDEக்கு நல்வரவு
+Name[te]=కెడిఈ కు స్వాగతం
+Name[tg]=Хуш омадед ба KDE
+Name[th]=ยินดีต้อนรับสู่ KDE
+Name[tr]=KDE'ye Hoş Geldiniz
+Name[tt]=KDE Räxim İt di</h3>
+Name[uk]=Ласкаво просимо до KDE
+Name[uz]=KDE'ga marhamat
+Name[uz@cyrillic]=KDE'га марҳамат
+Name[ven]=Riani tanganedza kha KDE
+Name[vi]=Chào mừng bạn đến với KDE
+Name[wa]=Bénvnowe dins KDE
+Name[xh]=Wamkelekile kwi KDE
+Name[zh_CN]=欢迎使用 KDE
+Name[zh_TW]=歡迎使用 KDE
+Name[zu]=Wamukulekile kwi-KDE
+
+X-DOC-Weight=-3000
diff --git a/khelpcenter/plugintraverser.cpp b/khelpcenter/plugintraverser.cpp
new file mode 100644
index 00000000..3f760962
--- /dev/null
+++ b/khelpcenter/plugintraverser.cpp
@@ -0,0 +1,117 @@
+/*
+ * This file is part of the KDE Help Center
+ *
+ * Copyright (C) 1999 Matthias Elter (me@kde.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "plugintraverser.h"
+#include "docmetainfo.h"
+#include "navigator.h"
+#include "navigatorappitem.h"
+#include "navigatoritem.h"
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+
+#include <qlistview.h>
+
+using namespace KHC;
+
+PluginTraverser::PluginTraverser( Navigator *navigator, QListView *parent )
+ : DocEntryTraverser(),
+ mListView( parent ),
+ mParentItem( 0 ),
+ mCurrentItem( 0 ),
+ mNavigator( navigator )
+{
+}
+
+PluginTraverser::PluginTraverser( Navigator *navigator, NavigatorItem *parent )
+ : DocEntryTraverser(),
+ mListView( 0 ),
+ mParentItem( parent ),
+ mCurrentItem( 0 ),
+ mNavigator( navigator )
+{
+}
+
+void PluginTraverser::process( DocEntry *entry )
+{
+ if ( !mListView && !mParentItem ) {
+ kdDebug( 1400 ) << "ERROR! Neither mListView nor mParentItem is set." << endl;
+ return;
+ }
+
+ if ( !entry->docExists() && !mNavigator->showMissingDocs() )
+ return;
+
+#if 0
+ kdDebug() << "PluginTraverser::process(): " << entry->name()
+ << " (weight: " << entry->weight() << " parent: "
+ << ( mParentItem ? mParentItem->name() : "0" ) << ")" << endl;
+#endif
+
+ if ( entry->khelpcenterSpecial() == "apps" ) {
+ NavigatorAppItem *appItem;
+ entry->setIcon( "kmenu" );
+ if ( mListView )
+ appItem = new NavigatorAppItem( entry, mListView, mCurrentItem );
+ else
+ appItem = new NavigatorAppItem( entry, mParentItem, mCurrentItem );
+ KConfig *cfg = kapp->config();
+ cfg->setGroup( "General" );
+ appItem->setRelpath( cfg->readPathEntry( "AppsRoot" ) );
+ mCurrentItem = appItem;
+ } else if ( entry->khelpcenterSpecial() == "scrollkeeper" ) {
+ if ( mParentItem ) {
+ mCurrentItem = mNavigator->insertScrollKeeperDocs( mParentItem, mCurrentItem );
+ }
+ return;
+ } else {
+ if ( mListView )
+ mCurrentItem = new NavigatorItem( entry, mListView, mCurrentItem );
+ else
+ mCurrentItem = new NavigatorItem( entry, mParentItem, mCurrentItem );
+
+ if (entry->khelpcenterSpecial() == "applets" ) {
+ mNavigator->insertAppletDocs( mCurrentItem );
+ } else if ( entry->khelpcenterSpecial() == "kinfocenter" ||
+ entry->khelpcenterSpecial() == "kcontrol" ||
+ entry->khelpcenterSpecial() == "konqueror" ) {
+ mNavigator->insertParentAppDocs( entry->khelpcenterSpecial(), mCurrentItem );
+ } else if ( entry->khelpcenterSpecial() == "kioslave" ) {
+ mNavigator->insertIOSlaveDocs( entry->khelpcenterSpecial(), mCurrentItem );
+ } else if ( entry->khelpcenterSpecial() == "info" ) {
+ mNavigator->insertInfoDocs( mCurrentItem );
+ } else {
+ return;
+ }
+ mCurrentItem->setPixmap( 0, SmallIcon( "contents2" ) );
+ }
+}
+
+DocEntryTraverser *PluginTraverser::createChild( DocEntry * /*entry*/ )
+{
+ if ( mCurrentItem ) {
+ return new PluginTraverser( mNavigator, mCurrentItem );
+ }
+ kdDebug( 1400 ) << "ERROR! mCurrentItem is not set." << endl;
+ return 0;
+}
+
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/plugintraverser.h b/khelpcenter/plugintraverser.h
new file mode 100644
index 00000000..be37017a
--- /dev/null
+++ b/khelpcenter/plugintraverser.h
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the KDE Help Center
+ *
+ * Copyright (C) 1999 Matthias Elter (me@kde.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef KHC_PLUGINTRAVERSER_H
+#define KHC_PLUGINTRAVERSER_H
+
+#include "docentrytraverser.h"
+
+class QListView;
+class QListViewItem;
+
+namespace KHC {
+ class Navigator;
+ class NavigatorItem;
+
+ class PluginTraverser : public DocEntryTraverser
+ {
+ public:
+ PluginTraverser( Navigator *navigator, QListView *parent );
+ PluginTraverser( Navigator *navigator, NavigatorItem *parent );
+
+ virtual void process( DocEntry *entry );
+
+ virtual DocEntryTraverser *createChild( DocEntry *entry );
+
+ private:
+ QListView *mListView;
+ NavigatorItem *mParentItem;
+ NavigatorItem *mCurrentItem;
+
+ Navigator *mNavigator;
+ };
+}
+
+#endif // KHC_PLUGINTRAVERSER_H
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/prefs.kcfgc b/khelpcenter/prefs.kcfgc
new file mode 100644
index 00000000..ae03d9c4
--- /dev/null
+++ b/khelpcenter/prefs.kcfgc
@@ -0,0 +1,6 @@
+# Code generation options for kconfig_compiler
+File=khelpcenter.kcfg
+ClassName=Prefs
+Singleton=true
+Mutators=true
+GlobalEnums=true
diff --git a/khelpcenter/scopeitem.h b/khelpcenter/scopeitem.h
new file mode 100644
index 00000000..33152060
--- /dev/null
+++ b/khelpcenter/scopeitem.h
@@ -0,0 +1,50 @@
+#ifndef SCOPEITEM_H
+#define SCOPEITEM_H
+
+#include <qlistview.h>
+
+#include "docmetainfo.h"
+
+namespace KHC {
+
+class ScopeItem : public QCheckListItem
+{
+ public:
+ ScopeItem( QListView *parent, DocEntry *entry )
+ : QCheckListItem( parent, entry->name(), QCheckListItem::CheckBox ),
+ mEntry( entry ), mObserver( 0 ) {}
+
+ ScopeItem( QListViewItem *parent, DocEntry *entry )
+ : QCheckListItem( parent, entry->name(), QCheckListItem::CheckBox ),
+ mEntry( entry ), mObserver( 0 ) {}
+
+ DocEntry *entry()const { return mEntry; }
+
+ int rtti() const { return rttiId(); }
+
+ static int rttiId() { return 734678; }
+
+ class Observer
+ {
+ public:
+ virtual void scopeItemChanged( ScopeItem * ) = 0;
+ };
+
+ void setObserver( Observer *o ) { mObserver = o; }
+
+ protected:
+ void stateChange ( bool )
+ {
+ if ( mObserver ) mObserver->scopeItemChanged( this );
+ }
+
+ private:
+ DocEntry *mEntry;
+
+ Observer *mObserver;
+};
+
+}
+
+#endif
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/scrollkeepertreebuilder.cpp b/khelpcenter/scrollkeepertreebuilder.cpp
new file mode 100644
index 00000000..b2a363ea
--- /dev/null
+++ b/khelpcenter/scrollkeepertreebuilder.cpp
@@ -0,0 +1,200 @@
+/*
+ * This file is part of the KDE Help Center
+ *
+ * Copyright (C) 1999 Matthias Elter (me@kde.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "scrollkeepertreebuilder.h"
+
+#include "navigatoritem.h"
+#include "docentry.h"
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kprocio.h>
+
+#include <qdom.h>
+#include <qfile.h>
+#include <qregexp.h>
+
+using namespace KHC;
+
+ScrollKeeperTreeBuilder::ScrollKeeperTreeBuilder( QObject *parent, const char *name )
+ : QObject( parent, name )
+{
+ loadConfig();
+}
+
+void ScrollKeeperTreeBuilder::loadConfig()
+{
+ KConfig *cfg = kapp->config();
+ {
+ KConfigGroupSaver groupSaver( cfg, "ScrollKeeper" );
+ mShowEmptyDirs = cfg->readBoolEntry( "ShowEmptyDirs", false );
+ }
+}
+
+NavigatorItem *ScrollKeeperTreeBuilder::build( NavigatorItem *parent,
+ NavigatorItem *after )
+{
+ QString lang = KGlobal::locale()->language();
+
+ kdDebug(1400) << "ScrollKeeper language: " << lang << endl;
+
+ KProcIO proc;
+ proc << "scrollkeeper-get-content-list";
+ proc << lang;
+ connect(&proc,SIGNAL(readReady(KProcIO *)),SLOT(getContentsList(KProcIO *)));
+ if (!proc.start(KProcess::Block)) {
+ kdDebug(1400) << "Could not execute scrollkeeper-get-content-list" << endl;
+ return 0;
+ }
+
+ if (!QFile::exists(mContentsList)) {
+ kdDebug(1400) << "Scrollkeeper contents file '" << mContentsList
+ << "' does not exist." << endl;
+ return 0;
+ }
+
+ QDomDocument doc("ScrollKeeperContentsList");
+ QFile f(mContentsList);
+ if ( !f.open( IO_ReadOnly ) )
+ return 0;
+ if ( !doc.setContent( &f ) ) {
+ f.close();
+ return 0;
+ }
+ f.close();
+
+ // Create top-level item
+ mItems.append(parent);
+
+ QDomElement docElem = doc.documentElement();
+
+ NavigatorItem *result = 0;
+
+ QDomNode n = docElem.firstChild();
+ while( !n.isNull() ) {
+ QDomElement e = n.toElement();
+ if( !e.isNull() ) {
+ if (e.tagName() == "sect") {
+ NavigatorItem *createdItem;
+ insertSection( parent, after, e, createdItem );
+ if ( createdItem ) result = createdItem;
+ }
+ }
+ n = n.nextSibling();
+ }
+
+ return result;
+}
+
+void ScrollKeeperTreeBuilder::getContentsList( KProcIO *proc )
+{
+ QString filename;
+ proc->readln( filename, true );
+
+ mContentsList = filename;
+}
+
+int ScrollKeeperTreeBuilder::insertSection( NavigatorItem *parent,
+ NavigatorItem *after,
+ const QDomNode &sectNode,
+ NavigatorItem *&sectItem )
+{
+ DocEntry *entry = new DocEntry( "", "", "contents2" );
+ sectItem = new NavigatorItem( entry, parent, after );
+ sectItem->setAutoDeleteDocEntry( true );
+ mItems.append( sectItem );
+
+ int numDocs = 0; // Number of docs created in this section
+
+ QDomNode n = sectNode.firstChild();
+ while( !n.isNull() ) {
+ QDomElement e = n.toElement();
+ if( !e.isNull() ) {
+ if ( e.tagName() == "title" ) {
+ entry->setName( e.text() );
+ sectItem->updateItem();
+ } else if (e.tagName() == "sect") {
+ NavigatorItem *created;
+ numDocs += insertSection( sectItem, 0, e, created );
+ } else if (e.tagName() == "doc") {
+ insertDoc(sectItem,e);
+ ++numDocs;
+ }
+ }
+ n = n.nextSibling();
+ }
+
+ // Remove empty sections
+ if (!mShowEmptyDirs && numDocs == 0) {
+ delete sectItem;
+ sectItem = 0;
+ }
+
+ return numDocs;
+}
+
+void ScrollKeeperTreeBuilder::insertDoc( NavigatorItem *parent,
+ const QDomNode &docNode )
+{
+ DocEntry *entry = new DocEntry( "", "", "document2" );
+ NavigatorItem *docItem = new NavigatorItem( entry, parent );
+ docItem->setAutoDeleteDocEntry( true );
+ mItems.append( docItem );
+
+ QString url;
+
+ QDomNode n = docNode.firstChild();
+ while( !n.isNull() ) {
+ QDomElement e = n.toElement();
+ if( !e.isNull() ) {
+ if ( e.tagName() == "doctitle" ) {
+ entry->setName( e.text() );
+ docItem->updateItem();
+ } else if ( e.tagName() == "docsource" ) {
+ url.append( e.text() );
+ } else if ( e.tagName() == "docformat" ) {
+ QString mimeType = e.text();
+ if ( mimeType == "text/html") {
+ // Let the HTML part figure out how to get the doc
+ } else if ( mimeType == "text/xml" ) {
+ if ( url.left( 5 ) == "file:" ) url = url.mid( 5 );
+ url.prepend( "ghelp:" );
+#if 0
+ url.replace( QRegExp( ".xml$" ), ".html" );
+#endif
+ } else if ( mimeType == "text/sgml" ) {
+ // GNOME docs use this type. We don't have a real viewer for this.
+ url.prepend( "file:" );
+ } else if ( mimeType.left(5) == "text/" ) {
+ url.prepend( "file:" );
+ }
+ }
+ }
+ n = n.nextSibling();
+ }
+
+ entry->setUrl( url );
+}
+
+#include "scrollkeepertreebuilder.moc"
+// vim:sw=2:ts=2:et
diff --git a/khelpcenter/scrollkeepertreebuilder.h b/khelpcenter/scrollkeepertreebuilder.h
new file mode 100644
index 00000000..522e7b8f
--- /dev/null
+++ b/khelpcenter/scrollkeepertreebuilder.h
@@ -0,0 +1,59 @@
+/*
+ * This file is part of the KDE Help Center
+ *
+ * Copyright (C) 1999 Matthias Elter (me@kde.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef KHC_SCROLLKEEPERTREEBUILDER_H
+#define KHC_SCROLLKEEPERTREEBUILDER_H
+
+#include <qobject.h>
+#include <qptrlist.h>
+
+#include "navigatoritem.h"
+
+class KProcIO;
+
+class QDomNode;
+
+namespace KHC {
+
+class ScrollKeeperTreeBuilder : public QObject
+{
+ Q_OBJECT
+ public:
+ ScrollKeeperTreeBuilder( QObject *parent, const char *name = 0 );
+
+ NavigatorItem *build( NavigatorItem *parent, NavigatorItem *after );
+
+ private slots:
+ void getContentsList( KProcIO *proc );
+
+ private:
+ void loadConfig();
+ int insertSection( NavigatorItem *parent, NavigatorItem *after,
+ const QDomNode &sectNode, NavigatorItem *&created );
+ void insertDoc( NavigatorItem *parent, const QDomNode &docNode );
+
+ bool mShowEmptyDirs;
+ QString mContentsList;
+ QPtrList<NavigatorItem> mItems;
+};
+
+}
+
+#endif // KHC_SCROLLKEEPERTREEBUILDER_H
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/searchengine.cpp b/khelpcenter/searchengine.cpp
new file mode 100644
index 00000000..2156ee24
--- /dev/null
+++ b/khelpcenter/searchengine.cpp
@@ -0,0 +1,502 @@
+#include "stdlib.h"
+
+#include <qstylesheet.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kstandarddirs.h>
+#include <kprocess.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include "docmetainfo.h"
+#include "formatter.h"
+#include "view.h"
+#include "searchhandler.h"
+#include "prefs.h"
+
+#include "searchengine.h"
+
+namespace KHC
+{
+
+SearchTraverser::SearchTraverser( SearchEngine *engine, int level ) :
+ mMaxLevel( 999 ), mEngine( engine), mLevel( level )
+{
+#if 0
+ kdDebug() << "SearchTraverser(): " << mLevel
+ << " 0x" << QString::number( int( this ), 16 ) << endl;
+#endif
+}
+
+SearchTraverser::~SearchTraverser()
+{
+#if 0
+ kdDebug() << "~SearchTraverser(): " << mLevel
+ << " 0x" << QString::number( int( this ), 16 ) << endl;
+#endif
+
+ QString section;
+ if ( parentEntry() ) {
+ section = parentEntry()->name();
+ } else {
+ section = ("Unknown Section");
+ }
+
+ if ( !mResult.isEmpty() ) {
+ mEngine->view()->writeSearchResult(
+ mEngine->formatter()->sectionHeader( section ) );
+ mEngine->view()->writeSearchResult( mResult );
+ }
+}
+
+void SearchTraverser::process( DocEntry * )
+{
+ kdDebug() << "SearchTraverser::process()" << endl;
+}
+
+void SearchTraverser::startProcess( DocEntry *entry )
+{
+// kdDebug() << "SearchTraverser::startProcess(): " << entry->name() << " "
+// << "SEARCH: '" << entry->search() << "'" << endl;
+
+ if ( !mEngine->canSearch( entry ) || !entry->searchEnabled() ) {
+ mNotifyee->endProcess( entry, this );
+ return;
+ }
+
+// kdDebug() << "SearchTraverser::startProcess(): " << entry->identifier()
+// << endl;
+
+ SearchHandler *handler = mEngine->handler( entry->documentType() );
+
+ if ( !handler ) {
+ QString txt;
+ if ( entry->documentType().isEmpty() ) {
+ txt = i18n("Error: No document type specified.");
+ } else {
+ txt = i18n("Error: No search handler for document type '%1'.")
+ .arg( entry->documentType() );
+ }
+ showSearchError( handler, entry, txt );
+ return;
+ }
+
+ connectHandler( handler );
+
+ handler->search( entry, mEngine->words(), mEngine->maxResults(),
+ mEngine->operation() );
+
+// kdDebug() << "SearchTraverser::startProcess() done: " << entry->name() << endl;
+}
+
+void SearchTraverser::connectHandler( SearchHandler *handler )
+{
+ QMap<SearchHandler *,int>::Iterator it;
+ it = mConnectCount.find( handler );
+ int count = 0;
+ if ( it != mConnectCount.end() ) count = *it;
+ if ( count == 0 ) {
+ connect( handler, SIGNAL( searchError( SearchHandler *, DocEntry *, const QString & ) ),
+ SLOT( showSearchError( SearchHandler *, DocEntry *, const QString & ) ) );
+ connect( handler, SIGNAL( searchFinished( SearchHandler *, DocEntry *, const QString & ) ),
+ SLOT( showSearchResult( SearchHandler *, DocEntry *, const QString & ) ) );
+ }
+ mConnectCount[ handler ] = ++count;
+}
+
+void SearchTraverser::disconnectHandler( SearchHandler *handler )
+{
+ QMap<SearchHandler *,int>::Iterator it;
+ it = mConnectCount.find( handler );
+ if ( it == mConnectCount.end() ) {
+ kdError() << "SearchTraverser::disconnectHandler() handler not connected."
+ << endl;
+ } else {
+ int count = *it;
+ --count;
+ if ( count == 0 ) {
+ disconnect( handler, SIGNAL( searchError( SearchHandler *, DocEntry *, const QString & ) ),
+ this, SLOT( showSearchError( SearchHandler *, DocEntry *, const QString & ) ) );
+ disconnect( handler, SIGNAL( searchFinished( SearchHandler *, DocEntry *, const QString & ) ),
+ this, SLOT( showSearchResult( SearchHandler *, DocEntry *, const QString & ) ) );
+ }
+ mConnectCount[ handler ] = count;
+ }
+}
+
+DocEntryTraverser *SearchTraverser::createChild( DocEntry *parentEntry )
+{
+// kdDebug() << "SearchTraverser::createChild() level " << mLevel << endl;
+
+ if ( mLevel >= mMaxLevel ) {
+ ++mLevel;
+ return this;
+ } else {
+ DocEntryTraverser *t = new SearchTraverser( mEngine, mLevel + 1 );
+ t->setParentEntry( parentEntry );
+ return t;
+ }
+}
+
+DocEntryTraverser *SearchTraverser::parentTraverser()
+{
+// kdDebug() << "SearchTraverser::parentTraverser(): level: " << mLevel << endl;
+
+ if ( mLevel > mMaxLevel ) {
+ return this;
+ } else {
+ return mParent;
+ }
+}
+
+void SearchTraverser::deleteTraverser()
+{
+// kdDebug() << "SearchTraverser::deleteTraverser()" << endl;
+
+ if ( mLevel > mMaxLevel ) {
+ --mLevel;
+ } else {
+ delete this;
+ }
+}
+
+void SearchTraverser::showSearchError( SearchHandler *handler, DocEntry *entry, const QString &error )
+{
+// kdDebug() << "SearchTraverser::showSearchError(): " << entry->name()
+// << endl;
+
+ mResult += mEngine->formatter()->docTitle( entry->name() );
+ mResult += mEngine->formatter()->paragraph( error );
+
+ mEngine->logError( entry, error );
+
+ disconnectHandler( handler );
+
+ mNotifyee->endProcess( entry, this );
+}
+
+void SearchTraverser::showSearchResult( SearchHandler *handler, DocEntry *entry, const QString &result )
+{
+// kdDebug() << "SearchTraverser::showSearchResult(): " << entry->name()
+// << endl;
+
+ mResult += mEngine->formatter()->docTitle( entry->name() );
+ mResult += mEngine->formatter()->processResult( result );
+
+ disconnectHandler( handler );
+
+ mNotifyee->endProcess( entry, this );
+}
+
+void SearchTraverser::finishTraversal()
+{
+// kdDebug() << "SearchTraverser::finishTraversal()" << endl;
+
+ mEngine->view()->writeSearchResult( mEngine->formatter()->footer() );
+ mEngine->view()->endSearchResult();
+
+ mEngine->finishSearch();
+}
+
+
+SearchEngine::SearchEngine( View *destination )
+ : QObject(),
+ mProc( 0 ), mSearchRunning( false ), mView( destination ),
+ mRootTraverser( 0 )
+{
+ mLang = KGlobal::locale()->language().left( 2 );
+}
+
+SearchEngine::~SearchEngine()
+{
+ delete mRootTraverser;
+}
+
+bool SearchEngine::initSearchHandlers()
+{
+ QStringList resources = KGlobal::dirs()->findAllResources(
+ "appdata", "searchhandlers/*.desktop" );
+ QStringList::ConstIterator it;
+ for( it = resources.begin(); it != resources.end(); ++it ) {
+ QString filename = *it;
+ kdDebug() << "SearchEngine::initSearchHandlers(): " << filename << endl;
+ SearchHandler *handler = SearchHandler::initFromFile( filename );
+ if ( !handler || !handler->checkPaths() ) {
+ QString txt = i18n("Unable to initialize SearchHandler from file '%1'.")
+ .arg( filename );
+ kdWarning() << txt << endl;
+// KMessageBox::sorry( mView->widget(), txt );
+ } else {
+ QStringList documentTypes = handler->documentTypes();
+ QStringList::ConstIterator it;
+ for( it = documentTypes.begin(); it != documentTypes.end(); ++it ) {
+ mHandlers.insert( *it, handler );
+ }
+ }
+ }
+
+ if ( mHandlers.isEmpty() ) {
+ QString txt = i18n("No valid search handler found.");
+ kdWarning() << txt << endl;
+// KMessageBox::sorry( mView->widget(), txt );
+ return false;
+ }
+
+ return true;
+}
+
+void SearchEngine::searchStdout(KProcess *, char *buffer, int len)
+{
+ if ( !buffer || len == 0 )
+ return;
+
+ QString bufferStr;
+ char *p;
+ p = (char*) malloc( sizeof(char) * (len+1) );
+ p = strncpy( p, buffer, len );
+ p[len] = '\0';
+
+ mSearchResult += bufferStr.fromUtf8(p);
+
+ free(p);
+}
+
+void SearchEngine::searchStderr(KProcess *, char *buffer, int len)
+{
+ if ( !buffer || len == 0 )
+ return;
+
+ mStderr.append( QString::fromUtf8( buffer, len ) );
+}
+
+void SearchEngine::searchExited(KProcess *)
+{
+ kdDebug() << "Search terminated" << endl;
+ mSearchRunning = false;
+}
+
+bool SearchEngine::search( QString words, QString method, int matches,
+ QString scope )
+{
+ if ( mSearchRunning ) return false;
+
+ // These should be removed
+ mWords = words;
+ mMethod = method;
+ mMatches = matches;
+ mScope = scope;
+
+ // Saner variables to store search parameters:
+ mWordList = QStringList::split( " ", words );
+ mMaxResults = matches;
+ if ( method == "or" ) mOperation = Or;
+ else mOperation = And;
+
+ KConfig *cfg = KGlobal::config();
+ cfg->setGroup( "Search" );
+ QString commonSearchProgram = cfg->readPathEntry( "CommonProgram" );
+ bool useCommon = cfg->readBoolEntry( "UseCommonProgram", false );
+
+ if ( commonSearchProgram.isEmpty() || !useCommon ) {
+ if ( !mView ) {
+ return false;
+ }
+
+ QString txt = i18n("Search Results for '%1':").arg( QStyleSheet::escape(words) );
+
+ mStderr = "<b>" + txt + "</b>\n";
+
+ mView->beginSearchResult();
+ mView->writeSearchResult( formatter()->header( i18n("Search Results") ) );
+ mView->writeSearchResult( formatter()->title( txt ) );
+
+ if ( mRootTraverser ) {
+ kdDebug() << "SearchEngine::search(): mRootTraverser not null." << endl;
+ return false;
+ }
+ mRootTraverser = new SearchTraverser( this, 0 );
+ DocMetaInfo::self()->startTraverseEntries( mRootTraverser );
+
+ return true;
+ } else {
+ QString lang = KGlobal::locale()->language().left(2);
+
+ if ( lang.lower() == "c" || lang.lower() == "posix" )
+ lang = "en";
+
+ // if the string contains '&' replace with a '+' and set search method to and
+ if (mWords.find("&") != -1) {
+ mWords.replace("&", " ");
+ method = "and";
+ }
+
+ // replace whitespace with a '+'
+ mWords = mWords.stripWhiteSpace();
+ mWords = mWords.simplifyWhiteSpace();
+ mWords.replace(QRegExp("\\s"), "+");
+
+ commonSearchProgram = substituteSearchQuery( commonSearchProgram );
+
+ kdDebug() << "Common Search: " << commonSearchProgram << endl;
+
+ mProc = new KProcess();
+
+ QStringList cmd = QStringList::split( " ", commonSearchProgram );
+ QStringList::ConstIterator it;
+ for( it = cmd.begin(); it != cmd.end(); ++it ) {
+ QString arg = *it;
+ if ( arg.left( 1 ) == "\"" && arg.right( 1 ) =="\"" ) {
+ arg = arg.mid( 1, arg.length() - 2 );
+ }
+ *mProc << arg.utf8();
+ }
+
+ connect( mProc, SIGNAL( receivedStdout( KProcess *, char *, int ) ),
+ SLOT( searchStdout( KProcess *, char *, int ) ) );
+ connect( mProc, SIGNAL( receivedStderr( KProcess *, char *, int ) ),
+ SLOT( searchStderr( KProcess *, char *, int ) ) );
+ connect( mProc, SIGNAL( processExited( KProcess * ) ),
+ SLOT( searchExited( KProcess * ) ) );
+
+ mSearchRunning = true;
+ mSearchResult = "";
+ mStderr = "<b>" + commonSearchProgram + "</b>\n\n";
+
+ mProc->start(KProcess::NotifyOnExit, KProcess::All);
+
+ while (mSearchRunning && mProc->isRunning())
+ kapp->processEvents();
+
+ if ( !mProc->normalExit() || mProc->exitStatus() != 0 ) {
+ kdError() << "Unable to run search program '" << commonSearchProgram
+ << "'" << endl;
+ delete mProc;
+
+ return false;
+ }
+
+ delete mProc;
+
+ // modify the search result
+ mSearchResult = mSearchResult.replace("http://localhost/", "file:/");
+ mSearchResult = mSearchResult.mid( mSearchResult.find( '<' ) );
+
+ mView->beginSearchResult();
+ mView->writeSearchResult( mSearchResult );
+ mView->endSearchResult();
+
+ emit searchFinished();
+ }
+
+ return true;
+}
+
+QString SearchEngine::substituteSearchQuery( const QString &query )
+{
+ QString result = query;
+ result.replace( "%k", mWords );
+ result.replace( "%n", QString::number( mMatches ) );
+ result.replace( "%m", mMethod );
+ result.replace( "%l", mLang );
+ result.replace( "%s", mScope );
+
+ return result;
+}
+
+QString SearchEngine::substituteSearchQuery( const QString &query,
+ const QString &identifier, const QStringList &words, int maxResults,
+ Operation operation, const QString &lang )
+{
+ QString result = query;
+ result.replace( "%i", identifier );
+ result.replace( "%w", words.join( "+" ) );
+ result.replace( "%m", QString::number( maxResults ) );
+ QString o;
+ if ( operation == Or ) o = "or";
+ else o = "and";
+ result.replace( "%o", o );
+ result.replace( "%d", Prefs::indexDirectory() );
+ result.replace( "%l", lang );
+
+ return result;
+}
+
+Formatter *SearchEngine::formatter() const
+{
+ return mView->formatter();
+}
+
+View *SearchEngine::view() const
+{
+ return mView;
+}
+
+void SearchEngine::finishSearch()
+{
+ delete mRootTraverser;
+ mRootTraverser = 0;
+
+ emit searchFinished();
+}
+
+QString SearchEngine::errorLog() const
+{
+ return mStderr;
+}
+
+void SearchEngine::logError( DocEntry *entry, const QString &msg )
+{
+ mStderr += entry->identifier() + ": " + msg;
+}
+
+bool SearchEngine::isRunning() const
+{
+ return mSearchRunning;
+}
+
+SearchHandler *SearchEngine::handler( const QString &documentType ) const
+{
+ QMap<QString,SearchHandler *>::ConstIterator it;
+ it = mHandlers.find( documentType );
+
+ if ( it == mHandlers.end() ) return 0;
+ else return *it;
+}
+
+QStringList SearchEngine::words() const
+{
+ return mWordList;
+}
+
+int SearchEngine::maxResults() const
+{
+ return mMaxResults;
+}
+
+SearchEngine::Operation SearchEngine::operation() const
+{
+ return mOperation;
+}
+
+bool SearchEngine::canSearch( DocEntry *entry )
+{
+ return entry->docExists() && !entry->documentType().isEmpty() &&
+ handler( entry->documentType() );
+}
+
+bool SearchEngine::needsIndex( DocEntry *entry )
+{
+ if ( !canSearch( entry ) ) return false;
+
+ SearchHandler *h = handler( entry->documentType() );
+ if ( h->indexCommand( entry->identifier() ).isEmpty() ) return false;
+
+ return true;
+}
+
+}
+
+#include "searchengine.moc"
+
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/searchengine.h b/khelpcenter/searchengine.h
new file mode 100644
index 00000000..1528fe6d
--- /dev/null
+++ b/khelpcenter/searchengine.h
@@ -0,0 +1,151 @@
+#ifndef SEARCHENGINE_H
+#define SEARCHENGINE_H
+
+#include <qobject.h>
+#include <qptrlist.h>
+#include <qstring.h>
+
+#include <kpixmap.h>
+#include <kio/job.h>
+
+#include "docentrytraverser.h"
+
+class QWidget;
+class KProcess;
+class KConfig;
+class KHTMLPart;
+
+namespace KHC {
+
+class Formatter;
+class SearchEngine;
+class View;
+class SearchHandler;
+
+class SearchTraverser : public QObject, public DocEntryTraverser
+{
+ Q_OBJECT
+ public:
+ SearchTraverser( SearchEngine *engine, int level );
+ ~SearchTraverser();
+
+ void process( DocEntry * );
+
+ void startProcess( DocEntry * );
+
+ DocEntryTraverser *createChild( DocEntry * );
+
+ DocEntryTraverser *parentTraverser();
+
+ void deleteTraverser();
+
+ void finishTraversal();
+
+ protected:
+ void connectHandler( SearchHandler *handler );
+ void disconnectHandler( SearchHandler *handler );
+
+ protected slots:
+ void showSearchResult( SearchHandler *, DocEntry *, const QString &result );
+ void showSearchError( SearchHandler *, DocEntry *, const QString &error );
+
+ private:
+ const int mMaxLevel;
+
+ SearchEngine *mEngine;
+ int mLevel;
+
+ DocEntry *mEntry;
+ QString mJobData;
+
+ QString mResult;
+
+ QMap<SearchHandler *, int> mConnectCount;
+};
+
+
+class SearchEngine : public QObject
+{
+ Q_OBJECT
+ public:
+ enum Operation { And, Or };
+
+ SearchEngine( View * );
+ ~SearchEngine();
+
+ bool initSearchHandlers();
+
+ bool search( QString words, QString method = "and", int matches = 5,
+ QString scope = "" );
+
+ Formatter *formatter() const;
+ View *view() const;
+
+ QString substituteSearchQuery( const QString &query );
+
+ static QString substituteSearchQuery( const QString &query,
+ const QString &identifier, const QStringList &words, int maxResults,
+ Operation operation, const QString &lang );
+
+ void finishSearch();
+
+ /**
+ Append error message to error log.
+ */
+ void logError( DocEntry *entry, const QString &msg );
+
+ /**
+ Return error log.
+ */
+ QString errorLog() const;
+
+ bool isRunning() const;
+
+ SearchHandler *handler( const QString &documentType ) const;
+
+ QStringList words() const;
+ int maxResults() const;
+ Operation operation() const;
+
+ bool canSearch( DocEntry * );
+ bool needsIndex( DocEntry * );
+
+ signals:
+ void searchFinished();
+
+ protected slots:
+ void searchStdout(KProcess *proc, char *buffer, int buflen);
+ void searchStderr(KProcess *proc, char *buffer, int buflen);
+ void searchExited(KProcess *proc);
+
+ protected:
+ void processSearchQueue();
+
+ private:
+ KProcess *mProc;
+ bool mSearchRunning;
+ QString mSearchResult;
+
+ QString mStderr;
+
+ View *mView;
+
+ QString mWords;
+ int mMatches;
+ QString mMethod;
+ QString mLang;
+ QString mScope;
+
+ QStringList mWordList;
+ int mMaxResults;
+ Operation mOperation;
+
+ DocEntryTraverser *mRootTraverser;
+
+ QMap<QString, SearchHandler *> mHandlers;
+};
+
+}
+
+#endif
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/searchhandler.cpp b/khelpcenter/searchhandler.cpp
new file mode 100644
index 00000000..a25d2fe4
--- /dev/null
+++ b/khelpcenter/searchhandler.cpp
@@ -0,0 +1,249 @@
+/*
+ This file is part of KHelpCenter.
+
+ Copyright (c) 2005 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include "searchhandler.h"
+
+#include "searchengine.h"
+#include "prefs.h"
+#include "docentry.h"
+
+#include <kdesktopfile.h>
+#include <kprocess.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+
+#include <stdlib.h>
+
+using namespace KHC;
+
+SearchHandler::SearchHandler()
+{
+ mLang = KGlobal::locale()->language().left( 2 );
+}
+
+SearchHandler *SearchHandler::initFromFile( const QString &filename )
+{
+ SearchHandler *handler = new SearchHandler;
+
+ KDesktopFile file( filename );
+
+ handler->mSearchCommand = file.readEntry( "SearchCommand" );
+ handler->mSearchUrl = file.readEntry( "SearchUrl" );
+ handler->mIndexCommand = file.readEntry( "IndexCommand" );
+ handler->mDocumentTypes = file.readListEntry( "DocumentTypes" );
+
+ return handler;
+}
+
+QStringList SearchHandler::documentTypes() const
+{
+ return mDocumentTypes;
+}
+
+QString SearchHandler::indexCommand( const QString &identifier )
+{
+ QString cmd = mIndexCommand;
+ cmd.replace( "%i", identifier );
+ cmd.replace( "%d", Prefs::indexDirectory() );
+ cmd.replace( "%l", mLang );
+ return cmd;
+}
+
+bool SearchHandler::checkPaths() const
+{
+ if ( !mSearchCommand.isEmpty() && !checkBinary( mSearchCommand ) )
+ return false;
+
+ if ( !mIndexCommand.isEmpty() && !checkBinary( mIndexCommand ) )
+ return false;
+
+ return true;
+}
+
+bool SearchHandler::checkBinary( const QString &cmd ) const
+{
+ QString binary;
+
+ int pos = cmd.find( ' ' );
+ if ( pos < 0 ) binary = cmd;
+ else binary = cmd.left( pos );
+
+ return !KStandardDirs::findExe( binary ).isEmpty();
+}
+
+void SearchHandler::search( DocEntry *entry, const QStringList &words,
+ int maxResults,
+ SearchEngine::Operation operation )
+{
+ kdDebug() << "SearchHandler::search(): " << entry->identifier() << endl;
+
+ if ( !mSearchCommand.isEmpty() ) {
+ QString cmdString = SearchEngine::substituteSearchQuery( mSearchCommand,
+ entry->identifier(), words, maxResults, operation, mLang );
+
+ kdDebug() << "SearchHandler::search() CMD: " << cmdString << endl;
+
+ KProcess *proc = new KProcess();
+
+ QStringList cmd = QStringList::split( " ", cmdString );
+ QStringList::ConstIterator it;
+ for( it = cmd.begin(); it != cmd.end(); ++it ) {
+ QString arg = *it;
+ if ( arg.left( 1 ) == "\"" && arg.right( 1 ) =="\"" ) {
+ arg = arg.mid( 1, arg.length() - 2 );
+ }
+ *proc << arg.utf8();
+ }
+
+ connect( proc, SIGNAL( receivedStdout( KProcess *, char *, int ) ),
+ SLOT( searchStdout( KProcess *, char *, int ) ) );
+ connect( proc, SIGNAL( receivedStderr( KProcess *, char *, int ) ),
+ SLOT( searchStderr( KProcess *, char *, int ) ) );
+ connect( proc, SIGNAL( processExited( KProcess * ) ),
+ SLOT( searchExited( KProcess * ) ) );
+
+ SearchJob *searchJob = new SearchJob;
+ searchJob->mEntry = entry;
+ searchJob->mProcess = proc;
+ searchJob->mCmd = cmdString;
+
+ mProcessJobs.insert( proc, searchJob );
+
+ if ( !proc->start( KProcess::NotifyOnExit, KProcess::All ) ) {
+ QString txt = i18n("Error executing search command '%1'.").arg( cmdString );
+ emit searchFinished( this, entry, txt );
+ }
+ } else if ( !mSearchUrl.isEmpty() ) {
+ QString urlString = SearchEngine::substituteSearchQuery( mSearchUrl,
+ entry->identifier(), words, maxResults, operation, mLang );
+
+ kdDebug() << "SearchHandler::search() URL: " << urlString << endl;
+
+ KIO::TransferJob *job = KIO::get( KURL( urlString ) );
+ connect( job, SIGNAL( result( KIO::Job * ) ),
+ SLOT( slotJobResult( KIO::Job * ) ) );
+ connect( job, SIGNAL( data( KIO::Job *, const QByteArray & ) ),
+ SLOT( slotJobData( KIO::Job *, const QByteArray & ) ) );
+
+ SearchJob *searchJob = new SearchJob;
+ searchJob->mEntry = entry;
+ searchJob->mKioJob = job;
+ mKioJobs.insert( job, searchJob );
+ } else {
+ QString txt = i18n("No search command or URL specified.");
+ emit searchFinished( this, entry, txt );
+ return;
+ }
+}
+
+void SearchHandler::searchStdout( KProcess *proc, char *buffer, int len )
+{
+ if ( !buffer || len == 0 )
+ return;
+
+ QString bufferStr;
+ char *p;
+ p = (char*) malloc( sizeof(char) * ( len + 1 ) );
+ p = strncpy( p, buffer, len );
+ p[len] = '\0';
+
+ QMap<KProcess *, SearchJob *>::ConstIterator it = mProcessJobs.find( proc );
+ if ( it != mProcessJobs.end() ) {
+ (*it)->mResult += bufferStr.fromUtf8( p );
+ }
+
+ free( p );
+}
+
+void SearchHandler::searchStderr( KProcess *proc, char *buffer, int len )
+{
+ if ( !buffer || len == 0 )
+ return;
+
+ QMap<KProcess *, SearchJob *>::ConstIterator it = mProcessJobs.find( proc );
+ if ( it != mProcessJobs.end() ) {
+ (*it)->mError += QString::fromUtf8( buffer, len );
+ }
+}
+
+void SearchHandler::searchExited( KProcess *proc )
+{
+// kdDebug() << "SearchHandler::searchExited()" << endl;
+
+ QString result;
+ QString error;
+ DocEntry *entry = 0;
+
+ QMap<KProcess *, SearchJob *>::ConstIterator it = mProcessJobs.find( proc );
+ if ( it != mProcessJobs.end() ) {
+ SearchJob *j = *it;
+ entry = j->mEntry;
+ result = j->mResult;
+ error = "<em>" + j->mCmd + "</em>\n" + j->mError;
+
+ mProcessJobs.remove( proc );
+ delete j;
+ } else {
+ kdError() << "No search job for exited process found." << endl;
+ }
+
+ if ( proc->normalExit() && proc->exitStatus() == 0 ) {
+ emit searchFinished( this, entry, result );
+ } else {
+ emit searchError( this, entry, error );
+ }
+}
+
+void SearchHandler::slotJobResult( KIO::Job *job )
+{
+ QString result;
+ DocEntry *entry = 0;
+
+ QMap<KIO::Job *, SearchJob *>::ConstIterator it = mKioJobs.find( job );
+ if ( it != mKioJobs.end() ) {
+ SearchJob *j = *it;
+
+ entry = j->mEntry;
+ result = j->mResult;
+
+ mKioJobs.remove( job );
+ delete j;
+ }
+
+ if ( job->error() ) {
+ emit searchError( this, entry, i18n("Error: %1").arg( job->errorString() ) );
+ } else {
+ emit searchFinished( this, entry, result );
+ }
+}
+
+void SearchHandler::slotJobData( KIO::Job *job, const QByteArray &data )
+{
+// kdDebug() << "SearchHandler::slotJobData()" << endl;
+
+ QMap<KIO::Job *, SearchJob *>::ConstIterator it = mKioJobs.find( job );
+ if ( it != mKioJobs.end() ) {
+ (*it)->mResult += data.data();
+ }
+}
+
+#include "searchhandler.moc"
diff --git a/khelpcenter/searchhandler.h b/khelpcenter/searchhandler.h
new file mode 100644
index 00000000..3b0979bd
--- /dev/null
+++ b/khelpcenter/searchhandler.h
@@ -0,0 +1,97 @@
+/*
+ This file is part of KHelpCenter.
+
+ Copyright (c) 2005 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+#ifndef KHC_SEARCHHANDLER_H
+#define KHC_SEARCHHANDLER_H
+
+#include "searchengine.h"
+
+#include <qobject.h>
+#include <qstringlist.h>
+
+namespace KIO {
+class Job;
+}
+
+namespace KHC {
+
+class SearchJob
+{
+ public:
+ SearchJob() : mProcess( 0 ), mKioJob( 0 ) {}
+
+ DocEntry *mEntry;
+
+ KProcess *mProcess;
+ KIO::Job *mKioJob;
+
+ QString mCmd;
+
+ QString mResult;
+ QString mError;
+};
+
+class SearchHandler : public QObject
+{
+ Q_OBJECT
+ public:
+ static SearchHandler *initFromFile( const QString &filename );
+
+ void search( DocEntry *, const QStringList &words,
+ int maxResults = 10,
+ SearchEngine::Operation operation = SearchEngine::And );
+
+ QString indexCommand( const QString &identifier );
+
+ QStringList documentTypes() const;
+
+ bool checkPaths() const;
+
+ signals:
+ void searchFinished( SearchHandler *, DocEntry *, const QString & );
+ void searchError( SearchHandler *, DocEntry *, const QString & );
+
+ protected:
+ bool checkBinary( const QString &cmd ) const;
+
+ protected slots:
+ void searchStdout( KProcess *proc, char *buffer, int buflen );
+ void searchStderr( KProcess *proc, char *buffer, int buflen );
+ void searchExited( KProcess *proc );
+
+ void slotJobResult( KIO::Job *job );
+ void slotJobData( KIO::Job *, const QByteArray &data );
+
+ private:
+ SearchHandler();
+
+ QString mLang;
+
+ QString mSearchCommand;
+ QString mSearchUrl;
+ QString mIndexCommand;
+ QStringList mDocumentTypes;
+
+ QMap<KProcess *,SearchJob *> mProcessJobs;
+ QMap<KIO::Job *,SearchJob *> mKioJobs;
+};
+
+}
+
+#endif
diff --git a/khelpcenter/searchhandlers/Makefile.am b/khelpcenter/searchhandlers/Makefile.am
new file mode 100644
index 00000000..65f4060b
--- /dev/null
+++ b/khelpcenter/searchhandlers/Makefile.am
@@ -0,0 +1,10 @@
+searchhandlers_DATA = htdig.desktop man.desktop docbook.desktop
+
+searchhandlersdir = $(kde_datadir)/khelpcenter/searchhandlers
+
+kde_bin_SCRIPTS = khc_htdig.pl khc_htsearch.pl khc_mansearch.pl \
+ khc_docbookdig.pl
+
+htdigdata_DATA = htdig_long.html
+
+htdigdatadir = $(kde_datadir)/khelpcenter/searchhandlers/htdig
diff --git a/khelpcenter/searchhandlers/README.searchhandlers b/khelpcenter/searchhandlers/README.searchhandlers
new file mode 100644
index 00000000..cbbfbbbd
--- /dev/null
+++ b/khelpcenter/searchhandlers/README.searchhandlers
@@ -0,0 +1,61 @@
+KHelpcenter Search Handlers
+===========================
+
+Searching documents in KHelpcenter is handled by document-type-specific search
+handlers. Each searchable document provides provides a document type in its meta
+data and if a corresponding handler is found, it can be searched.
+
+Search handlers are described by a desktop file which is put in the khelpcenter
+app directory in a "searchhandlers" directory. The desktop file contains the
+information about which document types the handler covers, how to do a search
+query and how to create a search index.
+
+A search handler has to provide a command line tool based interface. There has
+to be a command to do a query and, if previous creation of an index is required,
+a command to create a search index. The search commands returns its results as
+HTML on stdout.
+
+
+Search Query
+------------
+
+KHelpcenter reads the command to execute for submitting a search query from the
+search handler's desktop file ("SearchCommand"). The search command can contain
+some symbols which are replaced by KHelpcenter with the data for the concrete
+search request:
+
+%i Identifier of document (usually the name of the document's desktop file)
+%w Words to be searched for
+%o Operation for combining multiple search words. Allowed values: "and" and
+ "or".
+%m Maximum number of results
+%d Directory containing search indices
+
+Search Query Result
+-------------------
+
+The result has to be returned as HTML page. The content of the <body> tag will
+be extracted and inserted in the search results page. If there is no body tag,
+the complete result text will be inserted.
+
+
+Building a Search Index
+-----------------------
+
+KHelpcenter reads the command to build a search index from the search handler's
+desktop file ("IndexCommand"). The indexing command can contain some symbols
+which are replaced by KHelpcenter with the data for the concrete index creation
+call:
+
+%i Identifier of document (usually the name of the document's desktop file)
+%d Directory containing search indices
+%p Path to document to be indexed
+
+Index Creation Result
+---------------------
+
+As result of the indexing command an index is created in the directory specified
+by KHelpcenter. The format and structure of the index is handler-specific. When
+index creation is finished the indexing command has to create a special file
+with the name "<identifier>.exists", where <identifier> has to have the value
+passed by the %i symbol. This file indicates the existance of the index.
diff --git a/khelpcenter/searchhandlers/docbook.desktop b/khelpcenter/searchhandlers/docbook.desktop
new file mode 100644
index 00000000..08208c18
--- /dev/null
+++ b/khelpcenter/searchhandlers/docbook.desktop
@@ -0,0 +1,6 @@
+[Desktop Entry]
+
+DocumentTypes=text/docbook
+
+SearchCommand=khc_htsearch.pl --docbook --indexdir=%d --config=%i --words=%w --method=%o --maxnum=%m --lang=en
+IndexCommand=khc_docbookdig.pl --indexdir=%d --docpath=%p --identifier=%i
diff --git a/khelpcenter/searchhandlers/htdig.desktop b/khelpcenter/searchhandlers/htdig.desktop
new file mode 100644
index 00000000..08cff6ec
--- /dev/null
+++ b/khelpcenter/searchhandlers/htdig.desktop
@@ -0,0 +1,6 @@
+[Desktop Entry]
+
+DocumentTypes=text/html
+
+SearchCommand=khc_htsearch.pl --indexdir=%d --config=%i --words=%w --method=%o --maxnum=%m --lang=%l
+IndexCommand=khc_htdig.pl --indexdir=%d --docpath=%p --identifier=%i --lang=%l
diff --git a/khelpcenter/searchhandlers/htdig_long.html b/khelpcenter/searchhandlers/htdig_long.html
new file mode 100644
index 00000000..a2e6e218
--- /dev/null
+++ b/khelpcenter/searchhandlers/htdig_long.html
@@ -0,0 +1,2 @@
+$(STARSRIGHT) <a href="$&(URL)">$&(TITLE) ($(MODIFIED))</a><br>
+$(EXCERPT)<br>
diff --git a/khelpcenter/searchhandlers/khc_docbookdig.pl.in b/khelpcenter/searchhandlers/khc_docbookdig.pl.in
new file mode 100755
index 00000000..63f78751
--- /dev/null
+++ b/khelpcenter/searchhandlers/khc_docbookdig.pl.in
@@ -0,0 +1,221 @@
+#!/usr/bin/perl
+#
+# Wrapper script for creating search indices for htdig.
+#
+# This file is part of KHelpcenter.
+#
+# Copyright (C) 2002 SuSE Linux AG, Nuernberg
+#
+# Author: Cornelius Schumacher <cschum@suse.de>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+use strict;
+
+use Getopt::Long;
+
+my $htdigdata = "/srv/www/htdig/common/";
+my $htdigbin = "/usr/bin";
+my $kdeprefix = "@prefix@";
+chomp $kdeprefix;
+
+my $dbg = 1;
+
+my ($indexdir, $docpath, $identifier, $lang, $help );
+
+GetOptions (
+ 'indexdir=s' => \$indexdir,
+ 'docpath=s' => \$docpath,
+ 'identifier=s' => \$identifier,
+ 'lang=s' => \$lang,
+ 'help' => \$help,
+);
+
+if ( $help ) {
+ usage();
+}
+
+if ( !$indexdir || !$docpath || !$identifier ) {
+ print STDERR "Missing arguments.\n";
+ usage();
+}
+
+&dbg( "INDEXDIR: $indexdir" );
+
+if ( !$lang ) { $lang = "en"; }
+
+my $tmpdir = "$indexdir/$identifier.tmp";
+if ( ! -e $tmpdir ) {
+ mkdir $tmpdir;
+}
+
+print "Creating index for <b>'$identifier'</b>\n";
+
+my $htdigconf = $indexdir;
+my $htdigdb = $indexdir;
+
+my $conffile = "$htdigconf/$identifier.conf";
+
+my $commondir = "$htdigdata/$lang";
+if ( !$lang || !-e $commondir ) {
+ $commondir = "$htdigdata/en";
+}
+if ( !-e $commondir ) { $commondir = $htdigdata; }
+
+my $locale;
+if ( $lang eq "de" ) { $locale = "de_DE"; }
+else { $locale = $lang; }
+
+my $startfile = "$tmpdir/index.html";
+
+if ( !open( START, ">$startfile" ) ) {
+ print STDERR "Unable to open '$startfile' for writing.\n";
+ exit 1;
+}
+
+$ENV{ PATH } = '/bin:/usr/bin';
+$ENV{ CDPATH } = '';
+$ENV{ ENV } = '';
+
+my $findpath = "$kdeprefix/share/doc/HTML/$lang/";
+my $findcmd = "find $findpath -name index.docbook";
+
+print STDERR "FINDCMD: $findcmd\n";
+
+if ( !open FIND, "$findcmd|" ) {
+ print STDERR "Unable to find docs.\n";
+ exit 1;
+}
+while ( <FIND> ) {
+ chomp;
+ my $path = $_;
+ $path =~ /$findpath(.*)\/index.docbook$/;
+ my $app = $1;
+ print START "<a href=\"help://$app/index.docbook\">$path</a>\n";
+}
+close START;
+
+my $mimetypefile = "$tmpdir/htdig_mime";
+if ( !open( MIME, ">$mimetypefile" ) ) {
+ print STDERR "Unable to open '$mimetypefile' for writing.\n";
+ exit 1;
+}
+print MIME << "EOT";
+text/html html
+text/docbook docbook
+EOT
+close MIME;
+
+my $parserfile = "$tmpdir/docbookparser";
+if ( !open( PARSER, ">$parserfile" ) ) {
+ print STDERR "Unable to open '$parserfile' for writing.\n";
+ exit 1;
+}
+print PARSER << "EOT";
+#! /bin/sh
+
+file=\$1
+shift
+mime=\$1
+shift
+
+if test "\$#" -gt 0; then
+ orig=\${1/file:\\//}
+ shift
+fi
+
+case "\$orig" in
+ help:/*)
+ orig=\${orig/help:\\//}
+ orig=\${orig/\/index.docbook/}
+ cd $kdeprefix/share/doc/HTML/en/\$orig
+ file=index.docbook
+ ;;
+ *)
+ file=\$orig
+ cd `dirname \$orig`
+ ;;
+esac
+
+echo "t apptitle"
+$kdeprefix/bin/meinproc --htdig "\$file"
+EOT
+close PARSER;
+chmod 0755, $parserfile;
+
+if ( !open( CONF, ">$conffile" ) ) {
+ print STDERR "Unable to open '$conffile' for writing.\n";
+ exit 1;
+}
+print CONF << "EOT";
+# htdig configuration for doc '$identifier'
+#
+# This file has been automatically created by KHelpcenter
+common_dir: $commondir
+locale: $locale
+database_dir: $htdigdb
+database_base: \${database_dir}/$identifier
+local_urls: help://=$kdeprefix/share/doc/HTML/en/ file://=/
+local_urls_only: true
+limit_urls_to: file:// help:/
+ignore_noindex: true
+max_hop_count: 4
+robotstxt_name: kdedig
+compression_level: 6
+template_map: Long long $kdeprefix/share/apps/khelpcenter/searchhandlers/htdig/htdig_long.html
+search_algorithm: exact:1 prefix:0.8
+maximum_pages: 1
+matches_per_page: 10
+start_url: file://$tmpdir/index.html
+external_parsers: text/docbook $parserfile
+valid_extensions: .docbook .html
+mime_types: $mimetypefile
+EOT
+close CONF;
+
+my $ret = system( "$htdigbin/htdig", "-v", "-s", "-i", "-c", $conffile );
+if ( $ret != 0 ) {
+ print STDERR "htdig failed\n";
+} else {
+ $ret = system( "$htdigbin/htmerge", "-c", $conffile );
+ if ( $ret != 0 ) { print STDERR "htmerge failed\n"; }
+}
+
+if ( $ret == 0 ) {
+ my $existsfile = "$indexdir/$identifier.exists";
+
+ if ( !open( EXISTS, ">$existsfile" ) ) {
+ print STDERR "Unable to open '$existsfile' for writing.\n";
+ exit 1;
+ }
+ print EXISTS "$identifier\n";
+ close EXISTS;
+
+ print "Finished successfully.\n";
+}
+
+exit $ret;
+
+sub dbg($)
+{
+ $dbg && print STDERR shift, "\n";
+}
+
+sub usage()
+{
+ print "Usage: khc_docbookdig.pl --indexdir <indexdir> --docpath <path> ";
+ print "--identifier <identifier>\n";
+ exit 1;
+}
diff --git a/khelpcenter/searchhandlers/khc_htdig.pl.in b/khelpcenter/searchhandlers/khc_htdig.pl.in
new file mode 100755
index 00000000..909d53fd
--- /dev/null
+++ b/khelpcenter/searchhandlers/khc_htdig.pl.in
@@ -0,0 +1,148 @@
+#!/usr/bin/perl
+#
+# Wrapper script for creating search indices for htdig.
+#
+# This file is part of the SuSE help system.
+#
+# Copyright (C) 2002 SuSE Linux AG, Nuernberg
+#
+# Author: Cornelius Schumacher <cschum@suse.de>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+use strict;
+
+use Getopt::Long;
+
+my $htdigdata = "/srv/www/htdig/common/";
+my $htdigbin = "/usr/bin";
+my $kdeprefix = "@prefix@";
+chomp $kdeprefix;
+
+my $dbg = 1;
+
+my ($indexdir, $docpath, $identifier, $lang, $help );
+
+GetOptions (
+ 'indexdir=s' => \$indexdir,
+ 'docpath=s' => \$docpath,
+ 'identifier=s' => \$identifier,
+ 'lang=s' => \$lang,
+ 'help' => \$help,
+);
+
+if ( $help ) {
+ usage();
+}
+
+if ( !$indexdir || !$docpath || !$identifier ) {
+ print STDERR "Missing arguments.\n";
+ usage();
+}
+
+if ( !$lang ) { $lang = "en"; }
+
+&dbg( "INDEXDIR: $indexdir" );
+
+print "Creating index for <b>'$identifier'</b>\n";
+
+my $htdigconf = $indexdir;
+my $htdigdb = $indexdir;
+
+my $conffile = "$htdigconf/$identifier.conf";
+
+if ( !open( CONF, ">$conffile" ) ) {
+ print STDERR "Unable to open '$conffile' for writing.\n";
+ exit 1;
+}
+
+my $commondir = "$htdigdata/$lang";
+if ( !$lang || !-e $commondir ) {
+ $commondir = "$htdigdata/en";
+}
+if ( !-e $commondir ) { $commondir = $htdigdata; }
+
+my $locale;
+if ( $lang eq "de" ) { $locale = "de_DE"; }
+else { $locale = $lang; }
+
+print CONF << "EOT";
+# htdig configuration for doc '$identifier'
+#
+# This file has been automatically created by KHelpcenter
+
+common_dir: $commondir
+locale: $locale
+database_dir: $htdigdb
+local_urls: http://localhost=
+local_urls_only: true
+limit_urls_to: http://localhost
+ignore_noindex: true
+max_hop_count: 4
+robotstxt_name: kdedig
+compression_level: 6
+template_map: Long long $kdeprefix/share/apps/khelpcenter/searchhandlers/htdig/htdig_long.html \\
+ Short short $htdigdata/short.html
+search_algorithm: exact:1 prefix:0.8
+maximum_pages: 1
+matches_per_page: 10
+database_base: \${database_dir}/$identifier
+start_url: http://localhost/$docpath
+# for pdf-files
+max_doc_size: 5000000
+external_parsers: application/pdf /usr/share/doc/packages/htdig/contrib/parse_doc.pl application/postscript /usr/share/doc/packages/htdig/contrib/parse_doc.pl
+#external_parsers: text/docbook /build/htdig/parser
+EOT
+
+close CONF;
+
+$ENV{ PATH } = '';
+$ENV{ CDPATH } = '';
+$ENV{ ENV } = '';
+
+my $ret = system( "$htdigbin/htdig", "-s", "-i", "-c", $conffile );
+if ( $ret != 0 ) {
+ print STDERR "htdig failed\n";
+} else {
+ $ret = system( "$htdigbin/htmerge", "-c", $conffile );
+ if ( $ret != 0 ) { print STDERR "htmerge failed\n"; }
+}
+
+if ( $ret == 0 ) {
+ my $existsfile = "$indexdir/$identifier.exists";
+
+ if ( !open( EXISTS, ">$existsfile" ) ) {
+ print STDERR "Unable to open '$existsfile' for writing.\n";
+ exit 1;
+ }
+ print EXISTS "$identifier\n";
+ close EXISTS;
+
+ print "Finished successfully.\n";
+}
+
+exit $ret;
+
+sub dbg($)
+{
+ $dbg && print STDERR shift, "\n";
+}
+
+sub usage()
+{
+ print "Usage: khc_htdig.pl --indexdir <indexdir> --docpath <path> ";
+ print "--identifier <identifier>\n";
+ exit 1;
+}
diff --git a/khelpcenter/searchhandlers/khc_htsearch.pl b/khelpcenter/searchhandlers/khc_htsearch.pl
new file mode 100755
index 00000000..451e858d
--- /dev/null
+++ b/khelpcenter/searchhandlers/khc_htsearch.pl
@@ -0,0 +1,117 @@
+#!/usr/bin/perl
+
+use strict;
+
+use Encode;
+use Getopt::Long;
+
+use open IO => ':utf8';
+use open ':std';
+
+my $htsearchpath="/srv/www/cgi-bin/htsearch";
+
+my $config;
+my $format;
+my $method;
+my $words;
+my $lang;
+my $docbook;
+my $indexdir;
+my $maxnum;
+
+GetOptions (
+ 'config=s' => \$config,
+ 'format=s' => \$format,
+ 'method=s' => \$method,
+ 'words=s' => \$words,
+ 'lang=s' => \$lang,
+ 'docbook' => \$docbook,
+ 'indexdir=s' => \$indexdir,
+ 'maxnum=s' => \$maxnum
+);
+
+if ( !$indexdir ) {
+ print STDERR "No index dir given.\n";
+ exit 1;
+}
+
+if ( !$lang ) { $lang = "en"; }
+
+my $charset = langCharset( $lang );
+
+$words = encode( $charset, $words );
+
+if ( !open( HTSEARCH, "-|", "$htsearchpath", "-c", "$indexdir/$config.conf",
+ "format=$format&method=$method&words=$words" ) )
+{
+ print "Can't execute htsearch at '$htsearchpath'.\n";
+ exit 1;
+}
+
+my ($body,$liststart,$ref,$link,$error,$errorOut);
+
+while( <HTSEARCH> ) {
+ if ( !$body ) {
+ print;
+ if ( /^<body/ ) { $body = 1; }
+ }
+ if ( /^<h3>/ ) {
+ print;
+ print "<ul>\n";
+ $liststart = 1;
+ }
+ if ( /^<img src.*<a href="(.*)">(.*)<\/a>/ ) {
+ $ref = $1;
+ $link = $2;
+
+ print STDERR "REF: $ref LINK: $link\n";
+
+ $ref =~ s/file:\/\/localhost//;
+
+ $ref =~ s/http:\/\/localhost\//file:\//;
+
+ if ( $docbook ) {
+ $ref =~ /help:\/\/(.*)\/index.docbook/;
+ my $app = $1;
+ $ref = "help:$app";
+
+ $link =~ s/apptitle/$app/;
+ }
+
+ print " <li><a href=\"$ref\">$link</a></li>\n";
+ }
+ if ( /^<h1>ht:\/\/Dig error/ ) {
+ $error = 1;
+ print "Htdig error:\n";
+ }
+ if ( $error && /^<pre>/ ) {
+ $errorOut = 1;
+ }
+ if ( $errorOut ) {
+ print;
+ if ( /^<\/pre>/ ) { $errorOut = 0; }
+ }
+}
+
+close HTSEARCH;
+
+if ( $liststart ) { print "</ul>\n"; }
+
+print "</body></html>\n";
+
+if ( $? != 0 ) { exit $?; }
+
+1;
+
+# Return charset used for given language
+sub langCharset( $ )
+{
+ my $lang = shift;
+ if ( $lang eq "cz" || $lang eq "hu" ) {
+ return "latin2";
+ } elsif ( $lang eq "kr" ) {
+ return "utf8";
+ } else {
+ return "latin1";
+ }
+}
diff --git a/khelpcenter/searchhandlers/khc_mansearch.pl b/khelpcenter/searchhandlers/khc_mansearch.pl
new file mode 100755
index 00000000..a68fde75
--- /dev/null
+++ b/khelpcenter/searchhandlers/khc_mansearch.pl
@@ -0,0 +1,84 @@
+#!/usr/bin/perl
+#
+# Script for searching man pages. The result is generated as HTML.
+#
+# This file is part of KHelpcenter.
+#
+# Copyright (C) 2002 SuSE Linux AG, Nuernberg
+#
+# Author: Cornelius Schumacher <cschum@suse.de>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+use strict;
+
+use Getopt::Long;
+
+my ( $words, $maxcount, $lang, $help );
+
+GetOptions (
+ 'maxcount=s' => \$maxcount,
+ 'words=s' => \$words,
+ 'lang=s' => \$lang,
+ 'help' => \$help
+);
+
+if ( $help ) {
+ print STDERR "Usage: khc_mansearch.pl --maxcount=n --words=<string> " .
+ "--lang=<languagecode>\n";
+ exit 1;
+}
+
+if ( !$words ) {
+ print STDERR "No search words given.\n";
+ exit;
+}
+
+# Perform search
+if ( !open( MAN, "-|", "apropos", $words ) ) {
+ print "Can't open apropos.\n";
+ exit 1;
+}
+my @results;
+while( <MAN> ) {
+# print "RAW:$_";
+ chop;
+ /^([^\s]+)\s+\((.*)\)\s+-\s+(.*)$/;
+ my $page = $1;
+ my $section = $2;
+ my $description = $3;
+
+ if ( $page ) { push @results, [ $page, $section, $description ]; }
+}
+close MAN;
+
+my $nummatches = @results;
+
+if ( $nummatches > 0 ) {
+ print "<ul>\n";
+
+ my $count = 0;
+ for my $result ( @results ) {
+ my ( $page, $section, $description ) = @$result;
+ my $url = "man:" . $page;
+ print "<li><a href=\"$url\">";
+ print "$page - $description</a></li>\n";
+ if ( ++$count == $maxcount ) { last; }
+ }
+
+ print "</ul>\n";
+}
+
+1;
diff --git a/khelpcenter/searchhandlers/man.desktop b/khelpcenter/searchhandlers/man.desktop
new file mode 100644
index 00000000..f9274384
--- /dev/null
+++ b/khelpcenter/searchhandlers/man.desktop
@@ -0,0 +1,5 @@
+[Desktop Entry]
+
+DocumentTypes=text/man
+
+SearchCommand=khc_mansearch.pl --words=%w --maxcount=%m
diff --git a/khelpcenter/searchwidget.cpp b/khelpcenter/searchwidget.cpp
new file mode 100644
index 00000000..a8f14096
--- /dev/null
+++ b/khelpcenter/searchwidget.cpp
@@ -0,0 +1,392 @@
+/*
+ * searchwidget.cpp - part of the KDE Help Center
+ *
+ * Copyright (C) 1999 Matthias Elter (me@kde.org)
+ * (C) 2000 Matthias Hoelzer-Kluepfel (hoelzer@kde.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qcombobox.h>
+#include <qlayout.h>
+
+#include <ksimpleconfig.h>
+#include <kapplication.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+
+#include "scopeitem.h"
+#include "docentrytraverser.h"
+#include "kcmhelpcenter.h"
+#include "prefs.h"
+#include "searchengine.h"
+
+#include "searchwidget.h"
+
+namespace KHC {
+
+SearchWidget::SearchWidget( SearchEngine *engine, QWidget *parent )
+ : QWidget( parent ), DCOPObject( "SearchWidget" ), mEngine( engine ),
+ mScopeCount( 0 )
+{
+ QBoxLayout *topLayout = new QVBoxLayout( this, 2, 2 );
+
+ QBoxLayout *hLayout = new QHBoxLayout( topLayout );
+
+ mMethodCombo = new QComboBox( this );
+ mMethodCombo->insertItem( i18n("and") );
+ mMethodCombo->insertItem( i18n("or") );
+
+ QLabel *l = new QLabel( mMethodCombo, i18n("&Method:"), this );
+
+ hLayout->addWidget( l );
+ hLayout->addWidget( mMethodCombo );
+
+ hLayout = new QHBoxLayout( topLayout );
+
+ mPagesCombo = new QComboBox( this );
+ mPagesCombo->insertItem( "5" );
+ mPagesCombo->insertItem( "10" );
+ mPagesCombo->insertItem( "25" );
+ mPagesCombo->insertItem( "50" );
+ mPagesCombo->insertItem( "1000" );
+
+ l = new QLabel( mPagesCombo, i18n("Max. &results:"), this );
+
+ hLayout->addWidget( l );
+ hLayout->addWidget( mPagesCombo );
+
+ hLayout = new QHBoxLayout( topLayout );
+
+ mScopeCombo = new QComboBox( this );
+ for (int i=0; i < ScopeNum; ++i ) {
+ mScopeCombo->insertItem( scopeSelectionLabel( i ) );
+ }
+ connect( mScopeCombo, SIGNAL( activated( int ) ),
+ SLOT( scopeSelectionChanged( int ) ) );
+
+ l = new QLabel( mScopeCombo, i18n("&Scope selection:"), this );
+
+ hLayout->addWidget( l );
+ hLayout->addWidget( mScopeCombo );
+
+ mScopeListView = new QListView( this );
+ mScopeListView->setRootIsDecorated( true );
+ mScopeListView->addColumn( i18n("Scope") );
+ topLayout->addWidget( mScopeListView, 1 );
+
+ QPushButton *indexButton = new QPushButton( i18n("Build Search &Index..."),
+ this );
+ connect( indexButton, SIGNAL( clicked() ), SIGNAL( showIndexDialog() ) );
+ topLayout->addWidget( indexButton );
+
+// FIXME: Use SearchHandler on double-clicked document
+#if 0
+ connect( mScopeListView, SIGNAL( doubleClicked( QListViewItem * ) ),
+ SLOT( scopeDoubleClicked( QListViewItem * ) ) );
+#endif
+ connect( mScopeListView, SIGNAL( clicked( QListViewItem * ) ),
+ SLOT( scopeClicked( QListViewItem * ) ) );
+}
+
+
+SearchWidget::~SearchWidget()
+{
+ writeConfig( KGlobal::config() );
+}
+
+
+void SearchWidget::readConfig( KConfig *cfg )
+{
+ cfg->setGroup( "Search" );
+
+ int scopeSelection = cfg->readNumEntry( "ScopeSelection", ScopeDefault );
+ mScopeCombo->setCurrentItem( scopeSelection );
+ if ( scopeSelection != ScopeDefault ) scopeSelectionChanged( scopeSelection );
+
+ mMethodCombo->setCurrentItem( Prefs::method() );
+ mPagesCombo->setCurrentItem( Prefs::maxCount() );
+
+ if ( scopeSelection == ScopeCustom ) {
+ cfg->setGroup( "Custom Search Scope" );
+ QListViewItemIterator it( mScopeListView );
+ while( it.current() ) {
+ if ( it.current()->rtti() == ScopeItem::rttiId() ) {
+ ScopeItem *item = static_cast<ScopeItem *>( it.current() );
+ item->setOn( cfg->readBoolEntry( item->entry()->identifier(),
+ item->isOn() ) );
+ }
+ ++it;
+ }
+ }
+
+ checkScope();
+}
+
+void SearchWidget::writeConfig( KConfig *cfg )
+{
+ cfg->setGroup( "Search" );
+
+ cfg->writeEntry( "ScopeSelection", mScopeCombo->currentItem() );
+ Prefs::setMethod( mMethodCombo->currentItem() );
+ Prefs::setMaxCount( mPagesCombo->currentItem() );
+
+ if ( mScopeCombo->currentItem() == ScopeCustom ) {
+ cfg->setGroup( "Custom Search Scope" );
+ QListViewItemIterator it( mScopeListView );
+ while( it.current() ) {
+ if ( it.current()->rtti() == ScopeItem::rttiId() ) {
+ ScopeItem *item = static_cast<ScopeItem *>( it.current() );
+ cfg->writeEntry( item->entry()->identifier(), item->isOn() );
+ }
+ ++it;
+ }
+ }
+}
+
+void SearchWidget::slotSwitchBoxes()
+{
+ QListViewItemIterator it( mScopeListView );
+ while( it.current() ) {
+ if ( it.current()->rtti() == ScopeItem::rttiId() ) {
+ ScopeItem *item = static_cast<ScopeItem *>( it.current() );
+ item->setOn( !item->isOn() );
+ }
+ ++it;
+ }
+
+ checkScope();
+}
+
+void SearchWidget::scopeSelectionChanged( int id )
+{
+ QListViewItemIterator it( mScopeListView );
+ while( it.current() ) {
+ if ( it.current()->rtti() == ScopeItem::rttiId() ) {
+ ScopeItem *item = static_cast<ScopeItem *>( it.current() );
+ bool state = item->isOn();
+ switch( id ) {
+ case ScopeDefault:
+ state = item->entry()->searchEnabledDefault();
+ break;
+ case ScopeAll:
+ state = true;
+ break;
+ case ScopeNone:
+ state = false;
+ break;
+ default:
+ break;
+ }
+ if ( state != item->isOn() ) {
+ item->setOn( state );
+ }
+ }
+ ++it;
+ }
+
+ checkScope();
+}
+
+QString SearchWidget::method()
+{
+ QString m = "and";
+ if ( mMethodCombo->currentItem() == 1)
+ m = "or";
+
+ return m;
+}
+
+int SearchWidget::pages()
+{
+ int p = mPagesCombo->currentText().toInt();
+
+ return p;
+}
+
+QString SearchWidget::scope()
+{
+ QString scope;
+
+ QListViewItemIterator it( mScopeListView );
+ while( it.current() ) {
+ if ( it.current()->rtti() == ScopeItem::rttiId() ) {
+ ScopeItem *item = static_cast<ScopeItem *>( it.current() );
+ if ( item->isOn() ) {
+ if ( !scope.isEmpty() ) scope += "&";
+ scope += "scope=" + item->entry()->identifier();
+ }
+ }
+ ++it;
+ }
+
+ return scope;
+}
+
+class ScopeTraverser : public DocEntryTraverser
+{
+ public:
+ ScopeTraverser( SearchWidget *widget, int level ) :
+ mWidget( widget ), mLevel( level ), mParentItem( 0 ) {}
+
+ ~ScopeTraverser()
+ {
+ if( mParentItem && !mParentItem->childCount() ) delete mParentItem;
+ }
+
+ void process( DocEntry *entry )
+ {
+ if ( mWidget->engine()->canSearch( entry ) &&
+ ( !mWidget->engine()->needsIndex( entry ) ||
+ entry->indexExists( Prefs::indexDirectory() ) ) ) {
+ ScopeItem *item = 0;
+ if ( mParentItem ) {
+ item = new ScopeItem( mParentItem, entry );
+ } else {
+ item = new ScopeItem( mWidget->listView(), entry );
+ }
+ item->setOn( entry->searchEnabled() );
+ }
+ }
+
+ DocEntryTraverser *createChild( DocEntry *entry )
+ {
+ if ( mLevel >= mNestingLevel ) {
+ ++mLevel;
+ return this;
+ } else {
+ ScopeTraverser *t = new ScopeTraverser( mWidget, mLevel + 1 );
+ QListViewItem *item = 0;
+ if ( mParentItem ) {
+ item = new QListViewItem( mParentItem, entry->name() );
+ } else {
+ item = new QListViewItem( mWidget->listView(), entry->name() );
+ }
+ item->setOpen( true );
+ t->mParentItem = item;
+ return t;
+ }
+ }
+
+ DocEntryTraverser *parentTraverser()
+ {
+ if ( mLevel > mNestingLevel ) return this;
+ else return mParent;
+ }
+
+ void deleteTraverser()
+ {
+ if ( mLevel > mNestingLevel ) --mLevel;
+ else delete this;
+ }
+
+ private:
+ SearchWidget *mWidget;
+ int mLevel;
+ QListViewItem *mParentItem;
+
+ static int mNestingLevel;
+};
+
+int ScopeTraverser::mNestingLevel = 2;
+
+void SearchWidget::searchIndexUpdated()
+{
+ KGlobal::config()->reparseConfiguration();
+ updateScopeList();
+ update();
+}
+
+void SearchWidget::updateScopeList()
+{
+ mScopeListView->clear();
+
+ ScopeTraverser t( this, 0 );
+ DocMetaInfo::self()->traverseEntries( &t );
+
+ checkScope();
+}
+
+void SearchWidget::scopeDoubleClicked( QListViewItem *item )
+{
+ if ( !item || item->rtti() != ScopeItem::rttiId() ) return;
+ ScopeItem *scopeItem = static_cast<ScopeItem *>( item );
+
+ QString searchUrl = scopeItem->entry()->search();
+
+ kdDebug() << "DoubleClick: " << searchUrl << endl;
+
+ emit searchResult( searchUrl );
+}
+
+void SearchWidget::scopeClicked( QListViewItem * )
+{
+ checkScope();
+
+ mScopeCombo->setCurrentItem( ScopeCustom );
+}
+
+QString SearchWidget::scopeSelectionLabel( int id ) const
+{
+ switch( id ) {
+ case ScopeCustom:
+ return i18n("Custom");
+ case ScopeDefault:
+ return i18n("Default");
+ case ScopeAll:
+ return i18n("All");
+ case ScopeNone:
+ return i18n("None");
+ default:
+ return i18n("unknown");
+ }
+}
+
+void SearchWidget::checkScope()
+{
+ mScopeCount = 0;
+
+ QListViewItemIterator it( mScopeListView );
+ while( it.current() ) {
+ if ( it.current()->rtti() == ScopeItem::rttiId() ) {
+ ScopeItem *item = static_cast<ScopeItem *>( it.current() );
+ if ( item->isOn() ) {
+ ++mScopeCount;
+ }
+ item->entry()->enableSearch( item->isOn() );
+ }
+ ++it;
+ }
+
+ emit scopeCountChanged( mScopeCount );
+}
+
+int SearchWidget::scopeCount() const
+{
+ return mScopeCount;
+}
+
+}
+
+#include "searchwidget.moc"
+
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/searchwidget.h b/khelpcenter/searchwidget.h
new file mode 100644
index 00000000..1200bcfa
--- /dev/null
+++ b/khelpcenter/searchwidget.h
@@ -0,0 +1,107 @@
+/*
+ * searchwidget.h - part of the KDE Help Center
+ *
+ * Copyright (C) 1999 Matthias Elter (me@kde.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __searchwidget_h__
+#define __searchwidget_h__
+
+#include <qwidget.h>
+
+#include <dcopobject.h>
+
+#include "docmetainfo.h"
+
+class QCheckBox;
+class QListView;
+class QListViewItem;
+class QComboBox;
+
+class KLanguageCombo;
+class KConfig;
+
+class KCMHelpCenter;
+
+namespace KHC {
+
+class ScopeItem;
+class SearchEngine;
+
+class SearchWidget : public QWidget, public DCOPObject
+{
+ Q_OBJECT
+ K_DCOP
+
+ k_dcop:
+ ASYNC searchIndexUpdated(); // called from kcmhelpcenter
+
+ public:
+ SearchWidget ( SearchEngine *, QWidget *parent = 0 );
+ ~SearchWidget();
+
+ QString method();
+ int pages();
+ QString scope();
+
+ QListView *listView() { return mScopeListView; }
+
+ enum { ScopeDefault, ScopeAll, ScopeNone, ScopeCustom, ScopeNum };
+
+ QString scopeSelectionLabel( int ) const;
+
+ void readConfig( KConfig * );
+ void writeConfig( KConfig * );
+
+ int scopeCount() const;
+
+ SearchEngine *engine() const { return mEngine; }
+
+ signals:
+ void searchResult( const QString &url );
+ void scopeCountChanged( int );
+ void showIndexDialog();
+
+ public slots:
+ void slotSwitchBoxes();
+ void scopeSelectionChanged( int );
+ void updateScopeList();
+
+ protected:
+ void checkScope();
+
+ protected slots:
+ void scopeDoubleClicked( QListViewItem * );
+ void scopeClicked( QListViewItem * );
+
+ private:
+ void loadLanguages();
+
+ SearchEngine *mEngine;
+
+ QComboBox *mMethodCombo;
+ QComboBox *mPagesCombo;
+ QComboBox *mScopeCombo;
+ QListView *mScopeListView;
+
+ int mScopeCount;
+};
+
+}
+
+#endif
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/table-of-contents.xslt b/khelpcenter/table-of-contents.xslt
new file mode 100644
index 00000000..47b7fbb7
--- /dev/null
+++ b/khelpcenter/table-of-contents.xslt
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="1.0">
+
+<xsl:template match="book">
+<table-of-contents>
+<xsl:apply-templates select="chapter"/>
+</table-of-contents>
+</xsl:template>
+
+<xsl:template match="chapter">
+<chapter>
+<title><xsl:value-of select="title"/></title>
+<anchor><xsl:value-of select="@id"/></anchor>
+<xsl:apply-templates select="sect1"/>
+</chapter>
+</xsl:template>
+
+<xsl:template match="sect1">
+<section>
+<title><xsl:value-of select="title"/></title>
+<anchor><xsl:value-of select="@id"/></anchor>
+</section>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/khelpcenter/testmetainfo.cpp b/khelpcenter/testmetainfo.cpp
new file mode 100644
index 00000000..65ffd871
--- /dev/null
+++ b/khelpcenter/testmetainfo.cpp
@@ -0,0 +1,119 @@
+#include <qstringlist.h>
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kcmdlineargs.h>
+
+#include "docmetainfo.h"
+#include "docentrytraverser.h"
+
+using namespace KHC;
+
+class MyTraverser : public DocEntryTraverser
+{
+ public:
+ MyTraverser( const QString &indent = "" ) : mIndent( indent ) {}
+
+ void process( DocEntry *entry )
+ {
+ kdDebug() << mIndent << entry->name() << " - WEIGHT: " << entry->weight()
+ << endl;
+#if 0
+ if ( entry->parent() ) kdDebug() << mIndent << " PARENT: "
+ << entry->parent()->name() << endl;
+ if ( entry->nextSibling() ) kdDebug() << mIndent << " NEXT: "
+ << entry->nextSibling()->name() << endl;
+#endif
+ }
+
+ DocEntryTraverser *createChild( DocEntry * )
+ {
+ return new MyTraverser( mIndent + " " );
+ }
+
+ private:
+ QString mIndent;
+};
+
+class LinearTraverser : public DocEntryTraverser
+{
+ public:
+ void process( DocEntry *entry )
+ {
+ kdDebug() << "PROCESS: " << entry->name() << endl;
+ }
+
+ DocEntryTraverser *createChild( DocEntry * )
+ {
+ return this;
+ }
+
+ DocEntryTraverser *parentTraverser()
+ {
+ return this;
+ }
+
+ void deleteTraverser() {}
+};
+
+class AsyncTraverser : public DocEntryTraverser
+{
+ public:
+ AsyncTraverser( const QString &indent = "" ) : mIndent( indent )
+ {
+// kdDebug() << "AsyncTraverser()" << endl;
+ }
+
+ ~AsyncTraverser()
+ {
+// kdDebug() << "~AsyncTraverser()" << endl;
+ }
+
+ void process( DocEntry *entry )
+ {
+ kdDebug() << mIndent << entry->name() << endl;
+ }
+
+ DocEntryTraverser *createChild( DocEntry * )
+ {
+// kdDebug() << "AsyncTraverser::childTraverser()" << endl;
+ return new AsyncTraverser( mIndent + " " );
+ }
+
+ private:
+ QString mIndent;
+};
+
+int main(int argc,char **argv)
+{
+ KAboutData aboutData("testmetainfo","TestDocMetaInfo","0.1");
+ KCmdLineArgs::init(argc,argv,&aboutData);
+
+ KApplication app;
+
+ kdDebug() << "Scanning Meta Info" << endl;
+
+ QStringList langs;
+ langs << "en";
+// langs << "de";
+
+ DocMetaInfo::self()->scanMetaInfo( langs );
+
+ kdDebug() << "My TRAVERSE start" << endl;
+ MyTraverser t;
+ DocMetaInfo::self()->startTraverseEntries( &t );
+ kdDebug() << "My TRAVERSE end" << endl;
+
+ kdDebug() << "Linear TRAVERSE start" << endl;
+ LinearTraverser l;
+ DocMetaInfo::self()->startTraverseEntries( &l );
+ kdDebug() << "Linear TRAVERSE end" << endl;
+
+ kdDebug() << "Async TRAVERSE start" << endl;
+ AsyncTraverser a;
+ DocMetaInfo::self()->startTraverseEntries( &a );
+ kdDebug() << "Async TRAVERSE end" << endl;
+}
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/toc.cpp b/khelpcenter/toc.cpp
new file mode 100644
index 00000000..6b2beadc
--- /dev/null
+++ b/khelpcenter/toc.cpp
@@ -0,0 +1,271 @@
+/*
+ * This file is part of the KDE Help Center
+ *
+ * Copyright (C) 2002 Frerich Raabe (raabe@kde.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "toc.h"
+
+#include "docentry.h"
+
+#include <kiconloader.h>
+#include <kprocess.h>
+#include <kstandarddirs.h>
+#include <kdebug.h>
+
+#include <qdir.h>
+#include <qfileinfo.h>
+
+#include <sys/stat.h>
+
+using namespace KHC;
+
+class TOCItem : public NavigatorItem
+{
+ public:
+ TOCItem( TOC *parent, QListViewItem *parentItem, QListViewItem *after, const QString &text );
+
+ const TOC *toc() const { return m_toc; }
+
+ private:
+ TOC *m_toc;
+};
+
+class TOCChapterItem : public TOCItem
+{
+ public:
+ TOCChapterItem( TOC *toc, NavigatorItem *parent, QListViewItem *after, const QString &title,
+ const QString &name );
+
+ virtual QString url();
+
+ private:
+ QString m_name;
+};
+
+class TOCSectionItem : public TOCItem
+{
+ public:
+ TOCSectionItem( TOC *toc, TOCChapterItem *parent, QListViewItem *after, const QString &title,
+ const QString &name );
+
+ virtual QString url();
+
+ private:
+ QString m_name;
+};
+
+TOC::TOC( NavigatorItem *parentItem )
+{
+ m_parentItem = parentItem;
+}
+
+void TOC::build( const QString &file )
+{
+ QFileInfo fileInfo( file );
+ QString fileName = fileInfo.absFilePath();
+ const QStringList resourceDirs = KGlobal::dirs()->resourceDirs( "html" );
+ QStringList::ConstIterator it = resourceDirs.begin();
+ QStringList::ConstIterator end = resourceDirs.end();
+ for ( ; it != end; ++it ) {
+ if ( fileName.startsWith( *it ) ) {
+ fileName.remove( 0, ( *it ).length() );
+ break;
+ }
+ }
+
+ QString cacheFile = fileName.replace( QDir::separator(), "__" );
+ m_cacheFile = locateLocal( "cache", "help/" + cacheFile );
+ m_sourceFile = file;
+
+ if ( cacheStatus() == NeedRebuild )
+ buildCache();
+ else
+ fillTree();
+}
+
+TOC::CacheStatus TOC::cacheStatus() const
+{
+ if ( !QFile::exists( m_cacheFile ) ||
+ sourceFileCTime() != cachedCTime() )
+ return NeedRebuild;
+
+ return CacheOk;
+}
+
+int TOC::sourceFileCTime() const
+{
+ struct stat stat_buf;
+ stat( QFile::encodeName( m_sourceFile ).data(), &stat_buf );
+
+ return stat_buf.st_ctime;
+}
+
+int TOC::cachedCTime() const
+{
+ QFile f( m_cacheFile );
+ if ( !f.open( IO_ReadOnly ) )
+ return 0;
+
+ QDomDocument doc;
+ if ( !doc.setContent( &f ) )
+ return 0;
+
+ QDomComment timestamp = doc.documentElement().lastChild().toComment();
+
+ return timestamp.data().stripWhiteSpace().toInt();
+}
+
+void TOC::buildCache()
+{
+ KProcess *meinproc = new KProcess;
+ connect( meinproc, SIGNAL( processExited( KProcess * ) ),
+ this, SLOT( meinprocExited( KProcess * ) ) );
+
+ *meinproc << locate( "exe", "meinproc" );
+ *meinproc << "--stylesheet" << locate( "data", "khelpcenter/table-of-contents.xslt" );
+ *meinproc << "--output" << m_cacheFile;
+ *meinproc << m_sourceFile;
+
+ meinproc->start( KProcess::NotifyOnExit );
+}
+
+void TOC::meinprocExited( KProcess *meinproc )
+{
+ if ( !meinproc->normalExit() || meinproc->exitStatus() != 0 ) {
+ delete meinproc;
+ return;
+ }
+
+ delete meinproc;
+
+ QFile f( m_cacheFile );
+ if ( !f.open( IO_ReadWrite ) )
+ return;
+
+ QDomDocument doc;
+ if ( !doc.setContent( &f ) )
+ return;
+
+ QDomComment timestamp = doc.createComment( QString::number( sourceFileCTime() ) );
+ doc.documentElement().appendChild( timestamp );
+
+ f.at( 0 );
+ QTextStream stream( &f );
+ stream.setEncoding( QTextStream::UnicodeUTF8 );
+ stream << doc.toString();
+
+ f.close();
+
+ fillTree();
+}
+
+void TOC::fillTree()
+{
+ QFile f( m_cacheFile );
+ if ( !f.open( IO_ReadOnly ) )
+ return;
+
+ QDomDocument doc;
+ if ( !doc.setContent( &f ) )
+ return;
+
+ TOCChapterItem *chapItem = 0;
+ QDomNodeList chapters = doc.documentElement().elementsByTagName( "chapter" );
+ for ( unsigned int chapterCount = 0; chapterCount < chapters.count(); chapterCount++ ) {
+ QDomElement chapElem = chapters.item( chapterCount ).toElement();
+ QDomElement chapTitleElem = childElement( chapElem, QString::fromLatin1( "title" ) );
+ QString chapTitle = chapTitleElem.text().simplifyWhiteSpace();
+ QDomElement chapRefElem = childElement( chapElem, QString::fromLatin1( "anchor" ) );
+ QString chapRef = chapRefElem.text().stripWhiteSpace();
+
+ chapItem = new TOCChapterItem( this, m_parentItem, chapItem, chapTitle, chapRef );
+
+ TOCSectionItem *sectItem = 0;
+ QDomNodeList sections = chapElem.elementsByTagName( "section" );
+ for ( unsigned int sectCount = 0; sectCount < sections.count(); sectCount++ ) {
+ QDomElement sectElem = sections.item( sectCount ).toElement();
+ QDomElement sectTitleElem = childElement( sectElem, QString::fromLatin1( "title" ) );
+ QString sectTitle = sectTitleElem.text().simplifyWhiteSpace();
+ QDomElement sectRefElem = childElement( sectElem, QString::fromLatin1( "anchor" ) );
+ QString sectRef = sectRefElem.text().stripWhiteSpace();
+
+ sectItem = new TOCSectionItem( this, chapItem, sectItem, sectTitle, sectRef );
+ }
+ }
+
+ m_parentItem->setOpen( true );
+}
+
+QDomElement TOC::childElement( const QDomElement &element, const QString &name )
+{
+ QDomElement e;
+ for ( e = element.firstChild().toElement(); !e.isNull(); e = e.nextSibling().toElement() )
+ if ( e.tagName() == name )
+ break;
+ return e;
+}
+
+void TOC::slotItemSelected( QListViewItem *item )
+{
+ TOCItem *tocItem;
+ if ( ( tocItem = dynamic_cast<TOCItem *>( item ) ) )
+ emit itemSelected( tocItem->entry()->url() );
+
+ item->setOpen( !item->isOpen() );
+}
+
+TOCItem::TOCItem( TOC *toc, QListViewItem *parentItem, QListViewItem *after, const QString &text )
+ : NavigatorItem( new DocEntry( text ), parentItem, after )
+{
+ setAutoDeleteDocEntry( true );
+ m_toc = toc;
+}
+
+TOCChapterItem::TOCChapterItem( TOC *toc, NavigatorItem *parent, QListViewItem *after,
+ const QString &title, const QString &name )
+ : TOCItem( toc, parent, after, title ),
+ m_name( name )
+{
+ setOpen( false );
+ entry()->setUrl(url());
+}
+
+QString TOCChapterItem::url()
+{
+ return "help:" + toc()->application() + "/" + m_name + ".html";
+}
+
+TOCSectionItem::TOCSectionItem( TOC *toc, TOCChapterItem *parent, QListViewItem *after,
+ const QString &title, const QString &name )
+ : TOCItem( toc, parent, after, title ),
+ m_name( name )
+{
+ setPixmap( 0, SmallIcon( "document" ) );
+ entry()->setUrl(url());
+}
+
+QString TOCSectionItem::url()
+{
+ if ( static_cast<TOCSectionItem *>( parent()->firstChild() ) == this )
+ return static_cast<TOCChapterItem *>( parent() )->url() + "#" + m_name;
+
+ return "help:" + toc()->application() + "/" + m_name + ".html";
+}
+
+#include "toc.moc"
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/toc.h b/khelpcenter/toc.h
new file mode 100644
index 00000000..09971adb
--- /dev/null
+++ b/khelpcenter/toc.h
@@ -0,0 +1,72 @@
+/*
+ * toc.h - part of the KDE Help Center
+ *
+ * Copyright (C) 2002 Frerich Raabe (raabe@kde.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef KHC_TOC_H
+#define KHC_TOC_H
+
+#include "navigatoritem.h"
+
+#include <qdom.h>
+#include <qlistview.h>
+#include <qobject.h>
+
+class KProcess;
+
+namespace KHC {
+
+class TOC : public QObject
+{
+ Q_OBJECT
+ public:
+ TOC( NavigatorItem *parentItem );
+
+ QString application() const { return m_application; }
+ void setApplication( const QString &application ) { m_application = application; }
+
+ public slots:
+ void build( const QString &file );
+
+ signals:
+ void itemSelected( const QString &url );
+
+ private slots:
+ void slotItemSelected( QListViewItem *item );
+ void meinprocExited( KProcess *meinproc );
+
+ private:
+ enum CacheStatus { NeedRebuild, CacheOk };
+
+ CacheStatus cacheStatus() const;
+ int sourceFileCTime() const;
+ int cachedCTime() const;
+ QDomElement childElement( const QDomElement &e, const QString &name );
+ void buildCache();
+ void fillTree();
+
+ QString m_application;
+ QString m_cacheFile;
+ QString m_sourceFile;
+
+ NavigatorItem *m_parentItem;
+};
+
+}
+
+#endif // KHC_TOC_H
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/treebuilder.cpp b/khelpcenter/treebuilder.cpp
new file mode 100644
index 00000000..e0320fad
--- /dev/null
+++ b/khelpcenter/treebuilder.cpp
@@ -0,0 +1,35 @@
+/*
+ * This file is part of the KDE Help Center
+ *
+ * Copyright (C) 2002 Frerich Raabe <raabe@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "treebuilder.h"
+
+using namespace KHC;
+
+TreeBuilder::TreeBuilder( QObject *parent, const char *name )
+ : QObject( parent, name )
+{
+}
+
+void TreeBuilder::selectURL( const QString & )
+{
+}
+
+#include "treebuilder.moc"
+
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/treebuilder.h b/khelpcenter/treebuilder.h
new file mode 100644
index 00000000..2ba2bd5c
--- /dev/null
+++ b/khelpcenter/treebuilder.h
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the KDE Help Center
+ *
+ * Copyright (C) 2002 Frerich Raabe <raabe@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef TREEBUILDER_H
+#define TREEBUILDER_H
+
+#include "qobject.h"
+
+#include <kurl.h>
+
+namespace KHC
+{
+
+class NavigatorItem;
+class TreeBuilder : public QObject
+{
+ Q_OBJECT
+ public:
+ TreeBuilder( QObject *parent, const char *name = 0 );
+
+ virtual void build( NavigatorItem *item ) = 0;
+
+ public slots:
+ virtual void selectURL( const QString &url );
+
+ signals:
+ void urlSelected( const KURL &url );
+};
+
+}
+
+#endif // TREEBUILDER_H
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/version.h b/khelpcenter/version.h
new file mode 100644
index 00000000..80243a92
--- /dev/null
+++ b/khelpcenter/version.h
@@ -0,0 +1,7 @@
+#ifndef __version_h__
+#define __version_h__
+
+#define HELPCENTER_VERSION KDE_VERSION_STRING
+
+#endif
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/view.cpp b/khelpcenter/view.cpp
new file mode 100644
index 00000000..36a12c9c
--- /dev/null
+++ b/khelpcenter/view.cpp
@@ -0,0 +1,387 @@
+#include "view.h"
+
+#include "formatter.h"
+#include "history.h"
+
+#include <dom/html_document.h>
+#include <dom/html_misc.h>
+#include <kaction.h>
+#include <kactioncollection.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <khtml_settings.h>
+#include <khtmlview.h>
+#include <klocale.h>
+#include <kpopupmenu.h>
+#include <kstandarddirs.h>
+
+#include <qfileinfo.h>
+#include <qclipboard.h>
+
+using namespace KHC;
+
+View::View( QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name, KHTMLPart::GUIProfile prof, KActionCollection *col )
+ : KHTMLPart( parentWidget, widgetName, parent, name, prof ), mState( Docu ), mActionCollection(col)
+{
+ setJScriptEnabled(false);
+ setJavaEnabled(false);
+ setPluginsEnabled(false);
+
+ mFormatter = new Formatter;
+ if ( !mFormatter->readTemplates() ) {
+ kdDebug() << "Unable to read Formatter templates." << endl;
+ }
+
+ m_zoomStepping = 10;
+
+ connect( this, SIGNAL( setWindowCaption( const QString & ) ),
+ this, SLOT( setTitle( const QString & ) ) );
+ connect( this, SIGNAL( popupMenu( const QString &, const QPoint& ) ),
+ this, SLOT( showMenu( const QString &, const QPoint& ) ) );
+
+ QString css = langLookup("common/kde-default.css");
+ if (!css.isEmpty())
+ {
+ QFile css_file(css);
+ if (css_file.open(IO_ReadOnly))
+ {
+ QTextStream s(&css_file);
+ QString stylesheet = s.read();
+ preloadStyleSheet("help:/common/kde-default.css", stylesheet);
+ }
+ }
+
+ view()->installEventFilter( this );
+}
+
+View::~View()
+{
+ delete mFormatter;
+}
+
+void View::copySelectedText()
+{
+ kapp->clipboard()->setText( selectedText() );
+}
+
+bool View::openURL( const KURL &url )
+{
+ if ( url.protocol().lower() == "about" )
+ {
+ showAboutPage();
+ return true;
+ }
+ mState = Docu;
+ return KHTMLPart::openURL( url );
+}
+
+void View::saveState( QDataStream &stream )
+{
+ stream << mState;
+ if ( mState == Docu )
+ KHTMLPart::saveState( stream );
+}
+
+void View::restoreState( QDataStream &stream )
+{
+ stream >> mState;
+ if ( mState == Docu )
+ KHTMLPart::restoreState( stream );
+ else if ( mState == About )
+ showAboutPage();
+}
+
+void View::showAboutPage()
+{
+ QString file = locate( "data", "khelpcenter/intro.html.in" );
+ if ( file.isEmpty() )
+ return;
+
+ QFile f( file );
+
+ if ( !f.open( IO_ReadOnly ) )
+ return;
+
+ mState = About;
+
+ emit started( 0 );
+
+ QTextStream t( &f );
+
+ QString res = t.read();
+
+ res = res.arg( i18n("Conquer your Desktop!") )
+ .arg( langLookup( "khelpcenter/konq.css" ) )
+ .arg( langLookup( "khelpcenter/pointers.png" ) )
+ .arg( langLookup( "khelpcenter/khelpcenter.png" ) )
+ .arg( i18n("Help Center") )
+ .arg( langLookup( "khelpcenter/lines.png" ) )
+ .arg( i18n( "Welcome to the K Desktop Environment" ) )
+ .arg( i18n( "The KDE team welcomes you to user-friendly UNIX computing" ) )
+ .arg( i18n( "KDE is a powerful graphical desktop environment for UNIX workstations. A\n"
+ "KDE desktop combines ease of use, contemporary functionality and outstanding\n"
+ "graphical design with the technological superiority of the UNIX operating\n"
+ "system." ) )
+ .arg( i18n( "What is the K Desktop Environment?" ) )
+ .arg( i18n( "Contacting the KDE Project" ) )
+ .arg( i18n( "Supporting the KDE Project" ) )
+ .arg( i18n( "Useful links" ) )
+ .arg( i18n( "Getting the most out of KDE" ) )
+ .arg( i18n( "General Documentation" ) )
+ .arg( i18n( "A Quick Start Guide to the Desktop" ) )
+ .arg( i18n( "KDE Users' guide" ) )
+ .arg( i18n( "Frequently asked questions" ) )
+ .arg( i18n( "Basic Applications" ) )
+ .arg( i18n( "The Kicker Desktop Panel" ) )
+ .arg( i18n( "The KDE Control Center" ) )
+ .arg( i18n( "The Konqueror File manager and Web Browser" ) )
+ .arg( langLookup( "khelpcenter/kdelogo2.png" ) );
+ begin( KURL( "about:khelpcenter" ) );
+ write( res );
+ end();
+ emit completed();
+}
+
+QString View::langLookup( const QString &fname )
+{
+ QStringList search;
+
+ // assemble the local search paths
+ const QStringList localDoc = KGlobal::dirs()->resourceDirs("html");
+
+ // look up the different languages
+ for (int id=localDoc.count()-1; id >= 0; --id)
+ {
+ QStringList langs = KGlobal::locale()->languageList();
+ langs.append( "en" );
+ langs.remove( "C" );
+ QStringList::ConstIterator lang;
+ for (lang = langs.begin(); lang != langs.end(); ++lang)
+ search.append(QString("%1%2/%3").arg(localDoc[id]).arg(*lang).arg(fname));
+ }
+
+ // try to locate the file
+ QStringList::Iterator it;
+ for (it = search.begin(); it != search.end(); ++it)
+ {
+ QFileInfo info(*it);
+ if (info.exists() && info.isFile() && info.isReadable())
+ return *it;
+
+ // Fall back to the index.docbook for this language if we couldn't find its
+ // specific docbook file. If we are not looking up docbook (images,
+ // css etc) then look in other languages first.
+ if ( ( *it ).endsWith( "docbook" ) )
+ {
+ QString file = (*it).left((*it).findRev('/')) + "/index.docbook";
+ info.setFile(file);
+ if (info.exists() && info.isFile() && info.isReadable())
+ {
+ return *it;
+ }
+ }
+ }
+
+ return QString::null;
+}
+
+void View::setTitle( const QString &title )
+{
+ mTitle = title;
+}
+
+void View::beginSearchResult()
+{
+ mState = Search;
+
+ begin();
+ mSearchResult = "";
+}
+
+void View::writeSearchResult( const QString &str )
+{
+ write( str );
+ mSearchResult += str;
+}
+
+void View::endSearchResult()
+{
+ end();
+ if ( !mSearchResult.isEmpty() ) emit searchResultCacheAvailable();
+}
+
+void View::beginInternal( const KURL &url )
+{
+ mInternalUrl = url;
+ begin();
+}
+
+KURL View::internalUrl() const
+{
+ return mInternalUrl;
+}
+
+void View::lastSearch()
+{
+ if ( mSearchResult.isEmpty() ) return;
+
+ mState = Search;
+
+ begin();
+ write( mSearchResult );
+ end();
+}
+
+void View::slotIncFontSizes()
+{
+ setZoomFactor( zoomFactor() + m_zoomStepping );
+}
+
+void View::slotDecFontSizes()
+{
+ setZoomFactor( zoomFactor() - m_zoomStepping );
+}
+
+void View::showMenu( const QString& url, const QPoint& pos)
+{
+ KPopupMenu* pop = new KPopupMenu(view());
+ if (url.isEmpty())
+ {
+ KAction *action;
+ action = mActionCollection->action("go_home");
+ if (action) action->plug(pop);
+
+ pop->insertSeparator();
+
+ action = mActionCollection->action("prevPage");
+ if (action) action->plug(pop);
+ action = mActionCollection->action("nextPage");
+ if (action) action->plug(pop);
+
+ pop->insertSeparator();
+
+ History::self().m_backAction->plug(pop);
+ History::self().m_forwardAction->plug(pop);
+ }
+ else
+ {
+ pop->insertItem(i18n("Copy Link Address"), this, SLOT(slotCopyLink()));
+ mCopyURL = completeURL(url).url();
+ }
+
+ pop->exec(pos);
+ delete pop;
+}
+
+void View::slotCopyLink()
+{
+ QApplication::clipboard()->setText(mCopyURL);
+}
+
+bool View::prevPage(bool checkOnly)
+{
+ const DOM::HTMLCollection links = htmlDocument().links();
+
+ // The first link on a page (top-left corner) would be the Prev link.
+ const DOM::Node prevLinkNode = links.item( 0 );
+ KURL prevURL = urlFromLinkNode( prevLinkNode );
+ if (!prevURL.isValid())
+ return false;
+
+ if (!checkOnly)
+ openURL( prevURL );
+ return true;
+}
+
+bool View::nextPage(bool checkOnly)
+{
+ const DOM::HTMLCollection links = htmlDocument().links();
+
+ KURL nextURL;
+
+ // If we're on the first page, the "Next" link is the last link
+ if ( baseURL().path().endsWith( "/index.html" ) )
+ nextURL = urlFromLinkNode( links.item( links.length() - 1 ) );
+ else
+ nextURL = urlFromLinkNode( links.item( links.length() - 2 ) );
+
+ if (!nextURL.isValid())
+ return false;
+
+ // If we get a mail link instead of a http URL, or the next link points
+ // to an index.html page (a index.html page is always the first page
+ // there can't be a Next link pointing to it!) there's probably nowhere
+ // to go. Next link at all.
+ if ( nextURL.protocol() == "mailto" ||
+ nextURL.path().endsWith( "/index.html" ) )
+ return false;
+
+ if (!checkOnly)
+ openURL( nextURL );
+ return true;
+}
+
+bool View::eventFilter( QObject *o, QEvent *e )
+{
+ if ( e->type() != QEvent::KeyPress ||
+ htmlDocument().links().length() == 0 )
+ return KHTMLPart::eventFilter( o, e );
+
+ QKeyEvent *ke = static_cast<QKeyEvent *>( e );
+ if ( ke->state() & Qt::ShiftButton && ke->key() == Key_Space ) {
+ // If we're on the first page, it does not make sense to go back.
+ if ( baseURL().path().endsWith( "/index.html" ) )
+ return KHTMLPart::eventFilter( o, e );
+
+ const QScrollBar * const scrollBar = view()->verticalScrollBar();
+ if ( scrollBar->value() == scrollBar->minValue() ) {
+ if (prevPage())
+ return true;
+ }
+ } else if ( ke->key() == Key_Space ) {
+ const QScrollBar * const scrollBar = view()->verticalScrollBar();
+ if ( scrollBar->value() == scrollBar->maxValue() ) {
+ if (nextPage())
+ return true;
+ }
+ }
+ return KHTMLPart::eventFilter( o, e );
+}
+
+KURL View::urlFromLinkNode( const DOM::Node &n ) const
+{
+ if ( n.isNull() || n.nodeType() != DOM::Node::ELEMENT_NODE )
+ return KURL();
+
+ DOM::Element elem = static_cast<DOM::Element>( n );
+
+ KURL href ( elem.getAttribute( "href" ).string() );
+ if ( !href.protocol().isNull() )
+ return href;
+
+ QString path = baseURL().path();
+ path.truncate( path.findRev( '/' ) + 1 );
+ path += href.url();
+
+ KURL url = baseURL();
+ url.setRef( QString::null );
+ url.setEncodedPathAndQuery( path );
+
+ return url;
+}
+
+void View::slotReload( const KURL &url )
+{
+ const_cast<KHTMLSettings *>( settings() )->init( kapp->config() );
+ KParts::URLArgs args = browserExtension()->urlArgs();
+ args.reload = true;
+ browserExtension()->setURLArgs( args );
+ if ( url.isEmpty() )
+ openURL( baseURL() );
+ else
+ openURL( url );
+}
+
+#include "view.moc"
+// vim:ts=2:sw=2:et
diff --git a/khelpcenter/view.h b/khelpcenter/view.h
new file mode 100644
index 00000000..9eb1d86b
--- /dev/null
+++ b/khelpcenter/view.h
@@ -0,0 +1,94 @@
+#ifndef __view_h__
+#define __view_h__
+
+#include <khtml_part.h>
+
+#include "glossary.h"
+#include "navigator.h"
+
+class KActionCollection;
+
+namespace DOM {
+ class Node;
+}
+
+namespace KHC {
+
+class Formatter;
+
+class View : public KHTMLPart
+{
+ Q_OBJECT
+ public:
+ View( QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name, KHTMLPart::GUIProfile prof,
+ KActionCollection *col );
+
+ ~View();
+
+ virtual bool openURL( const KURL &url );
+
+ virtual void saveState( QDataStream &stream );
+ virtual void restoreState( QDataStream &stream );
+
+ enum State { Docu, About, Search };
+
+ int state() const { return mState; }
+ QString title() const { return mTitle; }
+
+ static QString langLookup( const QString &fname );
+
+ void beginSearchResult();
+ void writeSearchResult( const QString & );
+ void endSearchResult();
+
+ void beginInternal( const KURL & );
+ KURL internalUrl() const;
+
+ int zoomStepping() const { return m_zoomStepping; }
+
+ Formatter *formatter() const { return mFormatter; }
+
+ void copySelectedText();
+
+ public slots:
+ void lastSearch();
+ void slotIncFontSizes();
+ void slotDecFontSizes();
+ void slotReload( const KURL &url = KURL() );
+ void slotCopyLink();
+ bool nextPage(bool checkOnly = false);
+ bool prevPage(bool checkOnly = false);
+
+ signals:
+ void searchResultCacheAvailable();
+
+ protected:
+ bool eventFilter( QObject *o, QEvent *e );
+
+ private slots:
+ void setTitle( const QString &title );
+ void showMenu( const QString& url, const QPoint& pos);
+
+ private:
+ void showAboutPage();
+ KURL urlFromLinkNode( const DOM::Node &n ) const;
+
+ int mState;
+ QString mTitle;
+
+ QString mSearchResult;
+ KURL mInternalUrl;
+
+ int m_zoomStepping;
+
+ Formatter *mFormatter;
+ KActionCollection *mActionCollection;
+ QString mCopyURL;
+};
+
+}
+
+#endif
+
+// vim:ts=2:sw=2:et