From 6e28050ef5483e624122b0bacb998c40664f78ee Mon Sep 17 00:00:00 2001
From: dimitri <dimitri@afe2bf4a-e733-0410-8a33-86f594647bc7>
Date: Mon, 20 Jul 2009 20:05:52 +0000
Subject: Release-1.5.9-20090720

---
 INSTALL                      |   4 +-
 README                       |   4 +-
 addon/doxywizard/Makefile.in |   6 +-
 configure                    |   2 +-
 doc/config.doc               |  37 +-
 doc/dbusxml.doc              | 141 +++++++
 doc/installdox_usage.doc     |   7 +-
 doc/starting.doc             |   8 +-
 examples/dbusxml.cfg         |  10 +
 examples/dbusxml.xml         |  78 ++++
 qtools/Doxyfile              |  15 +-
 src/commentcnv.l             |   2 +-
 src/config.xml               |  14 +-
 src/configoptions.cpp        |  21 +-
 src/dbusxmlscanner.cpp       | 874 +++++++++++++++++++++++++++++++++++++++++++
 src/dbusxmlscanner.h         |  57 +++
 src/docparser.h              |   1 +
 src/docsets.cpp              |   1 +
 src/doxygen.cpp              |  38 +-
 src/doxygen.h                |   1 -
 src/fortranscanner.l         |  23 +-
 src/ftvhelp.cpp              |   6 +-
 src/htmlgen.cpp              | 123 ++----
 src/index.cpp                |  72 +++-
 src/latexgen.cpp             |   9 +-
 src/libdoxygen.pro.in        |   2 +
 src/portable.cpp             |   5 +
 src/portable.h               |   1 +
 src/pre.l                    |   5 +-
 src/scanner.l                |  33 +-
 src/search.css               |  50 ++-
 src/search.js                | 352 ++++++++++++++---
 src/search_css.h             |  50 ++-
 src/search_js.h              | 352 ++++++++++++++---
 src/util.cpp                 |  45 +--
 src/util.h                   |   3 +-
 36 files changed, 2072 insertions(+), 380 deletions(-)
 create mode 100644 doc/dbusxml.doc
 create mode 100644 examples/dbusxml.cfg
 create mode 100644 examples/dbusxml.xml
 create mode 100644 src/dbusxmlscanner.cpp
 create mode 100644 src/dbusxmlscanner.h

diff --git a/INSTALL b/INSTALL
index 81b8294..012b839 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,7 +1,7 @@
-DOXYGEN Version 1.5.9-20090622
+DOXYGEN Version 1.5.9-20090720
 
 Please read the installation section of the manual 
 (http://www.doxygen.org/install.html) for instructions.
 
 --------
-Dimitri van Heesch (22 June 2009)
+Dimitri van Heesch (20 July 2009)
diff --git a/README b/README
index 8d60917..6d0ac8a 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-DOXYGEN Version 1.5.9_20090622
+DOXYGEN Version 1.5.9_20090720
 
 Please read INSTALL for compilation instructions.
 
@@ -17,4 +17,4 @@ to subscribe to the lists or to visit the archives.
 
 Enjoy,
 
-Dimitri van Heesch (dimitri@stack.nl) (22 June 2009)
+Dimitri van Heesch (dimitri@stack.nl) (20 July 2009)
diff --git a/addon/doxywizard/Makefile.in b/addon/doxywizard/Makefile.in
index fa459c2..75a3a6d 100644
--- a/addon/doxywizard/Makefile.in
+++ b/addon/doxywizard/Makefile.in
@@ -10,16 +10,16 @@
 # See the GNU General Public License for more details.
 # 
 
-QMAKE = qmake
+QMAKE=qmake
 
 all: Makefile.doxywizard  
 	$(MAKE) -f Makefile.doxywizard 
 
 Makefile.doxywizard: doxywizard.pro
-	$(QTDIR)/bin/qmake doxywizard.pro -o Makefile.doxywizard
+	$(QMAKE) doxywizard.pro -o Makefile.doxywizard
 
 qmake: 
-	$(QTDIR)/bin/qmake doxywizard.pro -o Makefile.doxywizard
+	$(QMAKE) doxywizard.pro -o Makefile.doxywizard
 
 clean: Makefile.doxywizard 
 	$(MAKE) -f Makefile.doxywizard clean 
diff --git a/configure b/configure
index 4675673..dc6bf06 100755
--- a/configure
+++ b/configure
@@ -20,7 +20,7 @@ doxygen_version_minor=5
 doxygen_version_revision=9
 
 #NOTE: Setting version_mmn to "NO" will omit mmn info from the package.
-doxygen_version_mmn=20090622
+doxygen_version_mmn=20090720
 
 bin_dirs=`echo $PATH | sed -e "s/:/ /g"`
 
diff --git a/doc/config.doc b/doc/config.doc
index 7f9fe92..4679a4c 100644
--- a/doc/config.doc
+++ b/doc/config.doc
@@ -1431,6 +1431,26 @@ FILE_VERSION_INFO = "cleartool desc -fmt \%Vn"
  If non-empty doxygen will try to run qhelpgenerator on the generated
  .qhp file.
 
+\anchor cfg_searchengine
+<dt>\c SEARCHENGINE <dd>
+ \addindex SEARCHENGINE
+ The \c SEARCHENGINE tag specifies whether or not the HTML output should
+ contain a search function. Possible values are \c YES and \c NO. 
+ If set to YES, doxygen will produce a search index, and a search box at
+ the top of each page (or in the side bar in case GENERATE_TREE is enabled).
+ The search engine is implemented using javascript and DHTML and should
+ work on any modern browser. 
+
+ It is possible to search using the keyboard;
+ to jump to the search box use access key + S (what the access key is
+ depends on the OS and browser, but it is typically CTRL, ALT/option, or both).
+ Inside the search box use the cursor down key to jump into the search 
+ results window, the results can be navigated using the cursor keys.
+ Press Enter to select an item or escape to cancel the search. The
+ filter options can be selected when the cursor is inside the search box
+ by pressing Shift+cursor down. Also here use the cursor keys to 
+ select a filter and enter or escape to activate or cancel the filter option.
+
 <!--
 \anchor cfg_qthelp_file 
 <dt>\c QTHELP_FILE <dd>
@@ -1488,7 +1508,7 @@ FILE_VERSION_INFO = "cleartool desc -fmt \%Vn"
  the \ref cfg_project_name "project name".
 
 \anchor cfg_use_inline_trees
-<dt>\c USE_INLINE_TREES
+<dt>\c USE_INLINE_TREES <dd>
  \addindex USE_INLINE_TREES
 By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, 
 and Class Hierarchy pages using a tree view instead of an ordered list.
@@ -2179,21 +2199,6 @@ remove the intermediate dot files that are used to generate the various graphs.
 
 
 </dl>
-\section config_search Search engine options
-\anchor cfg_searchengine
-<dl>
-
-<dt>\c SEARCHENGINE <dd>
- \addindex SEARCHENGINE
- The \c SEARCHENGINE tag specifies whether or not the HTML output should
- contain a search facility. Possible values are \c YES and \c NO. 
- If set to YES, doxygen will produce a search index and a PHP script
- to search through the index. For this to work the documentation should
- be viewed via a web-server running PHP version 4.1.0 or higher.
- (See http://www.php.net/manual/en/installation.php for installation 
- instructions).
-
-</dl>
 <h2>Examples</h2>
 
 Suppose you have a simple project consisting of two files: a source file 
diff --git a/doc/dbusxml.doc b/doc/dbusxml.doc
new file mode 100644
index 0000000..a8710cb
--- /dev/null
+++ b/doc/dbusxml.doc
@@ -0,0 +1,141 @@
+/*! \page dbusxml DBus XML output format
+
+\addindex dbusxml
+
+<p>Doxygen can generate documentation for DBus XML files.  This way
+DBus interfaces can be annotated with doxygen style comments, and
+without writing custom XML parsers.  Doxygen extracts its text from
+all XML comments starting with '*' or '!'.  An additional '<' can be
+used to assign the documentation string to the previous entity instead
+of the one following the comment.
+
+\section dbusxml_supported Supported XML elements and attributes
+
+<p>The following DBus XML elemets can be annotated:
+
+<ul>
+<li><b>interface</b>
+
+<li><b>method</b> or <b>signal</b>
+
+<li><b>arg</b>
+
+<li><b>property</b>
+
+</ul>
+
+Additional elements are supported. These are available once
+the xmlns "http://psiamp.org/dtd/doxygen_dbusxml.dtd" is
+available.
+
+<ul>
+<li><b>namespace</b>: This can be used to group other more of the
+additional elemets.  This element requires a <b>name</b> attribute.
+
+<li><b>enum</b> is used to define enums.  <b>value</b> element is
+    then used to define the individual values in the enum.  This element
+    requires the <b>name</b> and <b>type</b> attributes.  A
+    optional <b>named-type</b> attribute is allowed, referrencing typed
+    previously defined by one of the additional elements.  A enum name
+    can be used anywhere a type is required using the <b>named-type</b>
+    attribute.
+
+<li><b>flagset</b> is used to define sets of flags. Required and
+    optional attributes are identical to the ones used by <b>enum</b>.
+    While <b>enum</b>s assume the values to be consecutive, while
+    a <b>flagset</b> is values suitable for flags.  A flagset name
+    can be used anywhere a type is required using the <b>named-type</b>
+    attribute.
+
+<li><b>struct</b> is used to define structures. A <b>name</b>
+    attribute is required.
+
+<li><b>member</b> is used to define members of <b>structs</b>.  It
+    is valid inside <b>struct</b> elements. This
+    element requires <b>name</b> and <b>type</b> attributes.  In
+    addition to (or even instead of) the <b>type</b> attribute a
+    <b>named-type</b> attribute may be used to reference types defined
+    by <b>enum</b>, <b>flagset</b> or <b>struct</b>.
+
+\section dbusxml_example Example
+
+<pre>
+<?xml version="1.0" ?>
+<!-- Comment -->
+<!--*< File comment -->
+<node name="/SomeNode" xmlns:dx="http://psiamp.org/dtd/doxygen_dbusxml.dtd">
+  <!--* test struct outside a namespace and interface -->
+  <dx:struct name="StructOutsideNamespace">
+    <!--* member 1 -->
+    <dx:member name="member1" type="s"/>
+    <!--* complex member 1 -->
+    <dx:member name="complexMember1" type="(ssu)"/>
+  </dx:struct>
+
+  <!--* Test flag set -->
+  <dx:flagset name="flagset">
+    <!--* Flag 1 of flagset. -->
+    <dx:value name="FLAG1"/>
+  </dx:flagset>
+
+  <!--* namespace comment -->
+  <dx:namespace name="SomeNamespace">
+    <!--* struct inside a namespace -->
+    <dx:struct name="StructInNamespace">
+       <!--* member 2 -->
+       <dx:member name="member2" type="s"/>
+    </dx:struct>
+  </dx:namespace>
+  <!--* Documentation on the interface -->
+  <interface name="nl.stack.doxygen.test.interface">
+    <!--* Test Enum documentation -->
+    <dx:enum name="TestEnum">
+      <!--* key 1 with value 13 -->
+      <dx:value name="KEY1" value="13"/>
+      <!--* key 2 without a value -->
+      <dx:value name="KEY2"/>
+    </dx:enum>
+
+    <!--* struct inside a interface -->
+    <dx:struct name="StructInInterface">
+      <!--* member 3 -->
+      <dx:member name="member3" type="s"/>
+      <!--* Struct in a struct -->
+      <dx:struct name="StructInAStruct">
+        <!--* member4 -->
+        <dx:member name="member4" type="s"/>
+      </dx:struct>
+      <!--* struct member -->
+      <dx:member name="structMembor" type="(s)" named-type="StructInAStruct"/>
+    </dx:struct>
+    <!--* Document method
+
+          Some extended documentation for the method.
+
+          @param[in] input blah.
+          @param[out] output blub
+     -->
+    <method name="method">
+      <arg direction="in" name="input" type="(s(s))" named-type="::nl::stack::doxygen::test::interface::StructInInterface"/>
+      <arg direction="out" type="v" name="output"/>
+    </method>
+
+    <signal name="signal">
+      <!--*< Documentation for signal.
+
+             @param parameter some parameter.
+        -->
+      <arg name="parameter" type="s"/>
+    </signal>
+
+    <!--* property documentation -->
+    <property name="property" type="s" access="readwrite"/>
+
+    <!--* property documentation read-only -->
+    <property name="propertyRead" type="s" access="read"/>
+    <!--* property documentation write-only -->
+    <property name="propertyWrite" type="s" access="write"/>
+  </interface>
+</node>
+</pre>
+*/
diff --git a/doc/installdox_usage.doc b/doc/installdox_usage.doc
index 59057b1..b1415a5 100644
--- a/doc/installdox_usage.doc
+++ b/doc/installdox_usage.doc
@@ -18,14 +18,11 @@
 
 Installdox is a perl script that is generated by doxygen whenever
 tag files are used (See \c TAGFILES
-in section \ref config_extref)
-or the search engine is enabled (See \c SEARCHENGINE
-in section \ref config_search). The script is 
+in section \ref config_extref). The script is 
 located in the same directory where the HTML files are located. 
 
 Its purpose is to set the location of the external documentation 
-for each tag file and to set the correct links to the search engine 
-at install time.
+for each tag file at install time.
 
 Calling \c installdox with option <b>-h</b> at the command line 
 will give you a brief description of the usage of the program.
diff --git a/doc/starting.doc b/doc/starting.doc
index 29ebc39..8e3e0d2 100644
--- a/doc/starting.doc
+++ b/doc/starting.doc
@@ -157,12 +157,8 @@ a browser that supports cascading style sheets (CSS) should be used
 generated output). 
 
 Some of the features the HTML section (such as 
-\ref cfg_generate_treeview "GENERATE_TREEVIEW") require a browser that
-supports DHTML and Javascript. 
-
-If you plan to use the search engine (see 
-\ref cfg_searchengine "SEARCHENGINE"), you should view the HTML output 
-via a PHP-enabled web server (e.g. apache with the PHP module installed).
+\ref cfg_generate_treeview "GENERATE_TREEVIEW" or the search engine) 
+require a browser that supports DHTML and Javascript. 
 
 \subsection latex_out LaTeX output
 \addindex LaTeX
diff --git a/examples/dbusxml.cfg b/examples/dbusxml.cfg
new file mode 100644
index 0000000..3620a4a
--- /dev/null
+++ b/examples/dbusxml.cfg
@@ -0,0 +1,10 @@
+PROJECT_NAME      = "DBusXMLDocs"
+OUTPUT_DIRECTORY  = dbusxml
+GENERATE_LATEX    = NO
+GENERATE_MAN      = NO
+GENERATE_RTF      = NO
+CASE_SENSE_NAMES  = NO
+INPUT             = dbusxml.xml
+QUIET             = YES
+JAVADOC_AUTOBRIEF = YES
+EXTRACT_ALL       = YES
diff --git a/examples/dbusxml.xml b/examples/dbusxml.xml
new file mode 100644
index 0000000..4ab7f78
--- /dev/null
+++ b/examples/dbusxml.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" ?>
+<!-- Comment -->
+<!--*< File comment -->
+<node name="/SomeNode" xmlns:dx="http://psiamp.org/dtd/doxygen_dbusxml.dtd">
+  <!--* test struct outside a namespace and interface -->
+  <dx:struct name="StructOutsideNamespace">
+    <!--* member 1 -->
+    <dx:member name="member1" type="s"/>
+    <!--* complex member 1 -->
+    <dx:member name="complexMember1" type="(ssu)"/>
+  </dx:struct>
+
+  <!--* Test flag set -->
+  <dx:flagset name="flagset">
+    <!--* Flag 1 of flagset. -->
+    <dx:value name="FLAG1"/>
+  </dx:flagset>
+
+  <!--* namespace comment -->
+  <dx:namespace name="SomeNamespace">
+    <!--* struct inside a namespace -->
+    <dx:struct name="StructInNamespace">
+       <!--* member 2 -->
+       <dx:member name="member2" type="s"/>
+    </dx:struct>
+  </dx:namespace>
+  <!--* Documentation on the interface -->
+  <interface name="nl.stack.doxygen.test.interface">
+    <!--* Test Enum documentation -->
+    <dx:enum name="TestEnum">
+      <!--* key 1 with value 13 -->
+      <dx:value name="KEY1" value="13"/>
+      <!--* key 2 without a value -->
+      <dx:value name="KEY2"/>
+    </dx:enum>
+
+    <!--* struct inside a interface -->
+    <dx:struct name="StructInInterface">
+      <!--* member 3 -->
+      <dx:member name="member3" type="s"/>
+      <!--* Struct in a struct -->
+      <dx:struct name="StructInAStruct">
+        <!--* member4 -->
+        <dx:member name="member4" type="s"/>
+      </dx:struct>
+      <!--* struct member -->
+      <dx:member name="structMembor" type="(s)" named-type="StructInAStruct"/>
+    </dx:struct>
+    <!--* Document method
+
+          Some extended documentation for the method.
+
+          @param[in] input blah.
+          @param[out] output blub
+     -->
+    <method name="method">
+      <arg direction="in" name="input" type="(s(s))" named-type="::nl::stack::doxygen::test::interface::StructInInterface"/>
+      <arg direction="out" type="v" name="output"/>
+    </method>
+
+    <signal name="signal">
+      <!--*< Documentation for signal.
+
+             @param parameter some parameter.
+        -->
+      <arg name="parameter" type="s"/>
+    </signal>
+
+    <!--* property documentation -->
+    <property name="property" type="s" access="readwrite"/>
+
+    <!--* property documentation read-only -->
+    <property name="propertyRead" type="s" access="read"/>
+    <!--* property documentation write-only -->
+    <property name="propertyWrite" type="s" access="write"/>
+  </interface>
+</node>
+<!-- vim:set sw=2 sts=2 et ft=xml: -->
diff --git a/qtools/Doxyfile b/qtools/Doxyfile
index 3ee0cd3..21e3bd0 100644
--- a/qtools/Doxyfile
+++ b/qtools/Doxyfile
@@ -149,14 +149,15 @@ QHP_SECT_FILTER_ATTRS  =
 QHG_LOCATION           = 
 DISABLE_INDEX          = NO
 ENUM_VALUES_PER_LINE   = 4
-GENERATE_TREEVIEW      = YES
+GENERATE_TREEVIEW      = NO
 USE_INLINE_TREES       = NO
 TREEVIEW_WIDTH         = 250
 FORMULA_FONTSIZE       = 10
+SEARCHENGINE           = YES
 #---------------------------------------------------------------------------
 # configuration options related to the LaTeX output
 #---------------------------------------------------------------------------
-GENERATE_LATEX         = NO
+GENERATE_LATEX         = YES
 LATEX_OUTPUT           = 
 LATEX_CMD_NAME         = latex
 MAKEINDEX_CMD_NAME     = makeindex
@@ -164,11 +165,11 @@ COMPACT_LATEX          = NO
 PAPER_TYPE             = a4wide
 EXTRA_PACKAGES         = 
 LATEX_HEADER           = 
-PDF_HYPERLINKS         = NO
-USE_PDFLATEX           = NO
+PDF_HYPERLINKS         = YES
+USE_PDFLATEX           = YES
 LATEX_BATCHMODE        = NO
 LATEX_HIDE_INDICES     = NO
-LATEX_SOURCE_CODE      = NO
+LATEX_SOURCE_CODE      = YES
 #---------------------------------------------------------------------------
 # configuration options related to the RTF output
 #---------------------------------------------------------------------------
@@ -254,7 +255,3 @@ DOT_TRANSPARENT        = YES
 DOT_MULTI_TARGETS      = NO
 GENERATE_LEGEND        = YES
 DOT_CLEANUP            = YES
-#---------------------------------------------------------------------------
-# Options related to the search engine
-#---------------------------------------------------------------------------
-SEARCHENGINE           = YES
diff --git a/src/commentcnv.l b/src/commentcnv.l
index 33d0c04..c18605d 100644
--- a/src/commentcnv.l
+++ b/src/commentcnv.l
@@ -348,7 +348,7 @@ void replaceComment(int offset);
                                      copyToOutput(yytext,yyleng); 
 				     BEGIN(CComment); 
                                    }
-<Scan>"##"		           {
+<Scan>"#"("#")?		           {
                                      if (g_lang!=SrcLangExt_Python)
 				     {
 				       REJECT;
diff --git a/src/config.xml b/src/config.xml
index 882c96b..55d809d 100644
--- a/src/config.xml
+++ b/src/config.xml
@@ -898,6 +898,14 @@ when you change the font size after a successful doxygen run you need
 to manually remove any form_*.png images from the HTML output directory 
 to force them to be regenerated. 
 ' minval='8' maxval='50' defval='10' depends='GENERATE_HTML'/>
+    <option type='bool' id='SEARCHENGINE' docs='
+When the SEARCHENGINE tag is enable doxygen will generate a search box
+for the HTML output. The underlying search engine uses javascript 
+and DHTML and should work on any modern browser. Note that when using
+HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP) 
+there is already a search function so this one should typically 
+be disabled.
+' defval='1' depends='GENERATE_HTML'/>
   </group>
   <group name='LaTeX' docs='configuration options related to the LaTeX output'>
     <option type='bool' id='GENERATE_LATEX' docs='
@@ -1358,12 +1366,6 @@ If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
 remove the intermediate dot files that are used to generate 
 the various graphs. 
 ' defval='1' depends='HAVE_DOT'/>
-  </group>
-  <group name='Search' docs='Options related to the search engine'>
-    <option type='bool' id='SEARCHENGINE' docs='
-The SEARCHENGINE tag specifies whether or not a search engine should be 
-used. If set to NO the values of all tags below this one will be ignored. 
-' defval='0'/>
     <option type='obsolete' id='SHOW_USED_FILES'/>
     <option type='obsolete' id='USE_WINDOWS_ENCODING'/>
     <option type='obsolete' id='DETAILS_AT_TOP'/>
diff --git a/src/configoptions.cpp b/src/configoptions.cpp
index bea89b6..d87fb24 100644
--- a/src/configoptions.cpp
+++ b/src/configoptions.cpp
@@ -1323,6 +1323,16 @@ void addConfigOptions(Config *cfg)
                  8,50,10
                 );
   ci->addDependency("GENERATE_HTML");
+  //----
+  cb = cfg->addBool(
+                 "SEARCHENGINE",
+                 "When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript \n"
+                 "and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP) \n"
+                 "there is already a search function so this one should typically \n"
+                 "be disabled.",
+                 TRUE
+                );
+  cb->addDependency("GENERATE_HTML");
   //---------------------------------------------------------------------------
   cfg->addInfo("LaTeX","configuration options related to the LaTeX output");
   //---------------------------------------------------------------------------
@@ -2072,17 +2082,6 @@ void addConfigOptions(Config *cfg)
                  TRUE
                 );
   cb->addDependency("HAVE_DOT");
-  //---------------------------------------------------------------------------
-  cfg->addInfo("Search","Options related to the search engine");
-  //---------------------------------------------------------------------------
-
-  //----
-  cb = cfg->addBool(
-                 "SEARCHENGINE",
-                 "The SEARCHENGINE tag specifies whether or not a search engine should be \n"
-                 "used. If set to NO the values of all tags below this one will be ignored.",
-                 FALSE
-                );
   //----
   cfg->addObsolete("SHOW_USED_FILES");
   //----
diff --git a/src/dbusxmlscanner.cpp b/src/dbusxmlscanner.cpp
new file mode 100644
index 0000000..8a07d81
--- /dev/null
+++ b/src/dbusxmlscanner.cpp
@@ -0,0 +1,874 @@
+/******************************************************************************
+ *
+ *
+ *
+ * Copyright (C) 2009 by Tobias Hunger <tobias@aquazul.com>
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation under the terms of the GNU General Public License is hereby
+ * granted. No representations are made about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied warranty.
+ * See the GNU General Public License for more details.
+ *
+ * Documents produced by Doxygen are derivative works derived from the
+ * input used in their production; they are not affected by this license.
+ *
+ */
+
+#include "dbusxmlscanner.h"
+
+#include "commentscan.h"
+#include "entry.h"
+
+#include <qfile.h>
+#include <qxml.h>
+#include <qstring.h>
+
+#include "message.h"
+#include "util.h"
+
+// -----------------------------------------------------------------------
+// Convenience defines:
+// -----------------------------------------------------------------------
+
+#define CONDITION(cond, msg) \
+    do {\
+        if (cond)\
+        {\
+            if (m_errorString.isEmpty()) { m_errorString = msg; }\
+            return false;\
+        }\
+    }\
+    while (0)
+
+#define DOC_ERROR(msg) \
+    warn_doc_error(m_fileName.utf8().data(), lineNumber(), msg.utf8().data())
+
+#define COND_DOC_ERROR(cond, msg) \
+    do {\
+        if (cond)\
+        {\
+             DOC_ERROR(msg);\
+             return true;\
+        }\
+    }\
+    while (0)
+
+#define DBUS(name) isDBusElement(namespaceURI, localName, qName, name)
+#define EXTENSION(name) isExtensionElement(namespaceURI, localName, qName, name)
+
+// -----------------------------------------------------------------------
+// DBusXMLHandler class
+// -----------------------------------------------------------------------
+
+const QString EXTENSION_URI("http://psiamp.org/dtd/doxygen_dbusxml.dtd");
+
+class DBusXMLHandler : public QXmlDefaultHandler
+{
+public:
+    DBusXMLHandler(ParserInterface * parser,
+                   QXmlSimpleReader * reader,
+                   const char * file_name,
+                   Entry * root) :
+        m_parser(parser),
+        m_locator(reader),
+        m_currentEntry(0),
+        m_currentInterface(0),
+        m_currentMethod(0),
+        m_currentArgument(0),
+        m_currentProperty(0),
+        m_currentEnum(0),
+        m_fileName(file_name),
+        m_currentComment(0)
+    {
+        setDocumentLocator(&m_locator);
+
+        m_scopeCount = 0;
+
+        // Set up stack cleanup:
+        m_structStack.setAutoDelete(TRUE);
+        m_elementStack.setAutoDelete(TRUE);
+        m_scopeStack.setAutoDelete(TRUE);
+
+        openScopes(root);
+    }
+
+    ~DBusXMLHandler()
+    { closeScopes(); }
+
+    QString errorString()
+    { return m_errorString; }
+
+    bool startElement(const QString &namespaceURI,
+                      const QString &localName,
+                      const QString &qName,
+                      const QXmlAttributes &attributes)
+    {
+        // add to elements stack:
+        m_elementStack.append(new ElementData(qName));
+
+        // First we need a node.
+        if (DBUS("node"))
+        {
+            CONDITION(!m_currentNode.isEmpty(), "Node inside a node.");
+
+            const int idx(indexOf(attributes, "name"));
+            COND_DOC_ERROR(idx < 0, QString("Anonymous node found."));
+
+            m_currentNode = attributes.value(idx);
+            // A node is actually of little interest, so do nothing here.
+            return true;
+        }
+
+        // Then we need an interface.
+        if (DBUS("interface"))
+        {
+            // We need a nodeName for interfaces:
+            CONDITION(m_currentNode.isEmpty(), "Interface without a node.");
+            CONDITION(m_currentInterface, "Interface within another interface.");
+
+            const int idx(indexOf(attributes, "name"));
+            COND_DOC_ERROR(idx < 0, QString("Interface without a name found."));
+
+            // A interface is roughly equivalent to a class:
+            m_currentInterface = createEntry();
+
+            m_currentInterface->section = Entry::CLASS_SEC;
+            m_currentInterface->spec |= Entry::Interface;
+            m_currentInterface->type = "Interface";
+            m_currentInterface->name = substitute(attributes.value(idx), ".", "::");
+
+            openScopes(m_currentInterface);
+
+            return true;
+        }
+
+        if (DBUS("method") || DBUS("signal"))
+        {
+            // We need a interfaceName for methods and signals:
+            CONDITION(!m_currentInterface, "Method or signal found outside a interface.");
+            CONDITION(m_currentMethod, "Method or signal found inside another method or signal.");
+            CONDITION(m_currentProperty, "Methor or signal found inside a property.");
+            CONDITION(!m_structStack.isEmpty(), "Method or signal found inside a struct.");
+            CONDITION(m_currentEnum, "Methor or signal found inside a enum.");
+
+            const int idx(indexOf(attributes, "name"));
+            COND_DOC_ERROR(idx < 0, QString("Method or signal without a name found."));
+
+            m_currentMethod = createEntry();
+
+            m_currentMethod->section = Entry::FUNCTION_SEC;
+            m_currentMethod->name = attributes.value(idx);
+            m_currentMethod->mtype = Method;
+            m_currentMethod->type = "void";
+
+            if (DBUS("signal"))
+            { m_currentMethod->mtype = Signal; }
+        }
+
+        if (DBUS("arg"))
+        {
+            // We need a method for arguments:
+            CONDITION(!m_currentMethod, "Argument found outside a method or signal.");
+            CONDITION(m_currentArgument, "Argument found inside another argument.");
+
+            const int name_idx(indexOf(attributes, "name"));
+            COND_DOC_ERROR(name_idx < 0, QString("Argument without a name found."));
+            COND_DOC_ERROR(!hasType(attributes), QString("Argument without a type found."));
+
+            const int direction_idx(indexOf(attributes, "direction"));
+
+            if ((m_currentMethod->mtype == Signal &&
+                 direction_idx >= 0 &&
+                 attributes.value(direction_idx) != "in") ||
+                (m_currentMethod->mtype == Method &&
+                 direction_idx >= 0 &&
+                 attributes.value(direction_idx) != "in" &&
+                 attributes.value(direction_idx) != "out"))
+            {
+                m_errorString = "Invalid direction found.";
+                return false;
+            }
+
+            m_currentArgument = new Argument;
+            m_currentArgument->type = getType(attributes);
+            m_currentArgument->name = attributes.value(name_idx);
+            if (direction_idx >= 0)
+            { m_currentArgument->attrib = attributes.value(direction_idx); }
+            else
+            {
+                if (m_currentMethod->mtype == Signal)
+                { m_currentArgument->attrib = "in"; }
+                else
+                { m_currentArgument->attrib = "out"; }
+            }
+        }
+
+        if (DBUS("property"))
+        {
+            CONDITION(m_currentMethod, "Property found inside a method or signal.");
+            CONDITION(!m_currentInterface, "Property found outside an interface.");
+            CONDITION(m_currentProperty, "Property found inside another property.");
+            CONDITION(!m_structStack.isEmpty(), "Property found inside a struct.");
+            CONDITION(m_currentEnum, "Property found inside a enum.");
+
+            const int name_idx(indexOf(attributes, "name"));
+            COND_DOC_ERROR(name_idx < 0, QString("Anonymous property found."));
+            COND_DOC_ERROR(!hasType(attributes), QString("Property without a type found."));
+
+            const int access_idx(indexOf(attributes, "access"));
+            COND_DOC_ERROR(access_idx < 0, QString("Property without a access attribute found."));
+            COND_DOC_ERROR(attributes.value(access_idx) != "read" &&
+                           attributes.value(access_idx) != "write" &&
+                           attributes.value(access_idx) != "readwrite",
+                           QString("Property with invalid access attribute \"%1\" found.").
+                           arg(attributes.value(access_idx)));
+
+            m_currentProperty = createEntry();
+
+            m_currentProperty->section = Entry::FUNCTION_SEC;
+
+            if (attributes.value(access_idx) == "read" ||
+                attributes.value(access_idx) == "readwrite")
+            { m_currentProperty->spec |= Entry::Readable; }
+
+            if (attributes.value(access_idx) == "write" ||
+                attributes.value(access_idx) == "readwrite")
+            { m_currentProperty->spec |= Entry::Writable; }
+
+            m_currentProperty->name = attributes.value(name_idx);
+            m_currentProperty->mtype = Property;
+            m_currentProperty->type = getType(attributes);
+        }
+
+        if (EXTENSION("namespace"))
+        {
+            CONDITION(m_currentNode.isEmpty(), "Namespace found outside a node.");
+            CONDITION(m_currentInterface, "Namespace found inside an interface.");
+
+            const int idx(indexOf(attributes, "name"));
+            COND_DOC_ERROR(idx < 0, QString("Anonymous namespace found."));
+
+            m_namespaceStack.append(openNamespace(attributes.value(idx)));
+            openScopes(m_namespaceStack.last());
+        }
+
+        if (EXTENSION("struct"))
+        {
+            CONDITION(m_currentMethod, "Struct found inside a method or signal.");
+            CONDITION(m_currentProperty, "Struct found inside a property.");
+            CONDITION(m_currentEnum, "Struct found inside an enum.");
+
+            const int idx(indexOf(attributes, "name"));
+            COND_DOC_ERROR(idx < 0, QString("Anonymous struct found."));
+
+            Entry * current_struct = createEntry();
+            current_struct->section = Entry::CLASS_SEC;
+            current_struct->spec = Entry::Struct;
+            current_struct->name = attributes.value(idx);
+
+            openScopes(current_struct);
+
+            current_struct->type = current_struct->name + " struct";
+
+            m_structStack.append(new StructData(current_struct));
+        }
+
+        if (EXTENSION("member"))
+        {
+            CONDITION(m_structStack.isEmpty(), "Member found outside of struct.");
+
+            const int name_idx(indexOf(attributes, "name"));
+            COND_DOC_ERROR(name_idx < 0, QString("Anonymous member found."));
+            COND_DOC_ERROR(!hasType(attributes), QString("Member without a type found."));
+
+            createEntry();
+
+            m_currentEntry->section = Entry::VARIABLE_SEC;
+            m_currentEntry->name = attributes.value(name_idx);
+            m_currentEntry->type = getType(attributes);
+
+            QString type(getDBusType(m_currentEntry->type));
+            m_structStack.last()->type.append(type);
+        }
+
+        if (EXTENSION("enum") || EXTENSION("flagset"))
+        {
+            CONDITION(m_currentMethod, "Enum found inside a method or signal.");
+            CONDITION(m_currentProperty, "Enum found inside a property.");
+
+            const int name_idx(indexOf(attributes, "name"));
+            COND_DOC_ERROR(name_idx < 0, QString("Anonymous enum found."));
+
+            const int type_idx(indexOf(attributes, "type"));
+            QString type = "u";
+            if (type_idx >= 0)
+            { type = attributes.value(type_idx); }
+            if (type != "y" && type != "q" && type != "u" && type != "t")
+            { DOC_ERROR(QString("Invalid enum type \"%1\" found.").arg(type)); }
+
+            m_currentEnum = createEntry();
+            m_currentEnum->section = Entry::ENUM_SEC;
+            m_currentEnum->name = attributes.value(name_idx);
+
+            openScopes(m_currentEnum);
+
+            m_currentEnum->type = m_currentEntry->name + " enum";
+
+            addNamedType(type);
+        }
+
+        if (EXTENSION("value"))
+        {
+            CONDITION(!m_currentEnum, "Value found outside an enum.");
+
+            const int name_idx(indexOf(attributes, "name"));
+            COND_DOC_ERROR(name_idx < 0, QString("Anonymous value found."));
+
+            const int value_idx(indexOf(attributes, "value"));
+
+            createEntry();
+
+            m_currentEntry->section = Entry::VARIABLE_SEC;
+            m_currentEntry->name = attributes.value(name_idx);
+            m_currentEntry->type = m_currentEnum->name; // "@"; // enum marker!
+            if (value_idx >= 0)
+            { m_currentEntry->initializer = attributes.value(value_idx); }
+        }
+
+        return true;
+    }
+
+    bool endElement(const QString &namespaceURI,
+                    const QString &localName,
+                    const QString &qName)
+    {
+        // Clean up elements stack:
+        // Since we made sure to get the elements in the proper order when
+        // adding we do not need to do so again here.
+        COND_DOC_ERROR(m_elementStack.last()->element != qName,
+                       QString("Malformed XML: Unexpected closing element found.").
+                       arg(m_elementStack.last()->element));
+        m_elementStack.removeLast();
+
+        // Interface:
+        if (DBUS("interface"))
+        {
+            m_currentInterface->endBodyLine = lineNumber();
+            closeScopes();
+            m_currentInterface = 0;
+        }
+
+        if (DBUS("method") || DBUS("signal"))
+        {
+            m_currentMethod->endBodyLine = lineNumber();
+            m_currentInterface->addSubEntry(m_currentMethod);
+            m_currentMethod = 0;
+        }
+
+        if (DBUS("property"))
+        {
+            m_currentProperty->endBodyLine = lineNumber();
+            m_currentInterface->addSubEntry(m_currentProperty);
+            m_currentProperty = 0;
+        }
+
+        if (DBUS("arg"))
+        {
+            m_currentMethod->argList->append(m_currentArgument);
+            m_currentArgument = 0;
+        }
+
+        if (EXTENSION("namespace"))
+        {
+            Entry * current = m_namespaceStack.last();
+            m_namespaceStack.removeLast();
+
+            current->endBodyLine = lineNumber();
+            closeScopes();
+        }
+
+        if (EXTENSION("struct"))
+        {
+            StructData * data = m_structStack.last();
+
+            data->entry->endBodyLine = lineNumber();
+
+            QString current_type;
+            current_type.append(QString("("));
+            current_type.append(data->type);
+            current_type.append(QString(")"));
+
+            addNamedType(current_type);
+
+            closeScopes();
+
+            m_structStack.removeLast();
+        }
+
+        if (EXTENSION("member"))
+        {
+           m_structStack.last()->entry->addSubEntry(m_currentEntry);
+        }
+
+        if (EXTENSION("enum") || EXTENSION("flagset"))
+        {
+            m_currentEnum->endBodyLine = lineNumber();
+            closeScopes();
+
+            m_currentEnum = 0;
+        }
+
+        if (EXTENSION("value"))
+        {
+            m_currentEntry->endBodyLine = lineNumber();
+
+            m_currentEnum->addSubEntry(m_currentEntry);
+        }
+
+        return true;
+    }
+
+    bool characters(const QString & /*chars*/)
+    { return true; }
+
+    bool comment(const QString & comment_)
+    {
+        if (m_currentComment)
+        { handleComment(); }
+
+        m_currentComment = new CommentData(m_fileName, lineNumber(), comment_);
+
+        if (!m_currentComment->shouldIgnore)
+        {
+            delete m_currentComment;
+            m_currentComment = 0;
+            return true;
+        }
+
+        if (m_currentComment->associateWithPrevious)
+        { handleComment(); }
+
+        return true;
+    }
+
+    void handleComment()
+    {
+        if (m_currentComment == 0 || m_currentEntry == 0)
+        { return; }
+
+        QCString text(m_currentComment->text);
+
+        m_currentEntry->docFile = m_currentComment->fileName;
+        m_currentEntry->docLine = m_currentComment->line;
+
+        int position(0);
+        bool needs_entry(false);
+        bool brief(false);
+        Protection prot(Public);
+
+        while (parseCommentBlock(m_parser,
+                                 m_currentEntry,
+                                 text, m_fileName.utf8().data(), lineNumber(),
+                                 brief, m_currentComment->isJavaStyle,
+                                 false,
+                                 prot,
+                                 position,
+                                 needs_entry))
+        {
+            if (needs_entry) { createEntry(); }
+        }
+        if (needs_entry) { createEntry(); }
+
+        delete m_currentComment;
+        m_currentComment = 0;
+    }
+
+    QXmlLocator * locator()
+    { return &m_locator; }
+
+    int lineNumber()
+    { return m_locator.lineNumber(); }
+
+    void setSection()
+    {
+        Entry * current = createEntry();
+        current->reset();
+
+        current->name    = m_fileName.utf8();
+        current->section = Entry::SOURCE_SEC;
+
+        // Open/Close the scope to do the bookkeeping:
+        openScopes(current);
+        closeScopes();
+    }
+
+private:
+    bool isDBusElement(const QString & namespaceURI,
+                       const QString & localName,
+                       const QString & qName,
+                       const QString & element)
+    {
+        return (namespaceURI.isEmpty() && localName == element && qName == element) ||
+               (namespaceURI.isEmpty() && localName.isEmpty() && qName == element);
+    }
+
+    bool isExtensionElement(const QString & namespaceURI,
+                            const QString & localName,
+                            const QString & qName,
+                            const QString & element)
+    {
+        // isNull happens in startelement if no URI is used.
+        if (namespaceURI.isNull())
+        { return false; }
+
+        // We are in a endElement: URI is always empty there:-(
+        if (namespaceURI.isEmpty())
+        { return qName == m_scopeStack.last()->extensionPrefix + element; }
+
+        // startElemennt: We need to save the qName prefix
+        // since endElement will forget about the namespaceURi:-(
+        if (namespaceURI == EXTENSION_URI)
+        {
+            int pos = qName.find(':');
+            m_scopeStack.last()->extensionPrefix = qName.left(pos + 1);
+        }
+
+        return namespaceURI == EXTENSION_URI && localName == element;
+    }
+
+    bool hasType(const QXmlAttributes & attributes)
+    {
+        const int type_idx(indexOf(attributes, "type"));
+        const int named_type_idx(indexOf(attributes, "named-type"));
+
+        return named_type_idx >= 0 || type_idx >= 0;
+    }
+
+    QString getType(const QXmlAttributes & attributes)
+    {
+        const int type_idx(indexOf(attributes, "type"));
+        const int named_type_idx(indexOf(attributes, "named-type"));
+
+        QString type;
+
+        if (named_type_idx >= 0)
+        {
+            type = attributes.value(named_type_idx);
+            if (!type.startsWith("::"))
+            { type = getCurrentScope(attributes.value(named_type_idx)); }
+            else
+            { type = type.mid(2); }
+            if (m_namedTypeMap.contains(type))
+            {
+                if (type_idx >= 0)
+                {
+                    const QString dbus_type(attributes.value(type_idx));
+                    if (dbus_type != m_namedTypeMap[type])
+                    {
+                        DOC_ERROR(QString("Type \"%1\" does not match up with "
+                                          "previous definition of named type \"%2\" (which was \"%3\".").
+                                          arg(dbus_type).
+                                          arg(type).
+                                          arg(m_namedTypeMap[type]));
+                    }
+                }
+                return type;
+            }
+
+            DOC_ERROR(QString("Undefined named type \"%1\" used.").arg(type));
+        }
+
+        if (type_idx >= 0)
+        {
+            type = attributes.value(type_idx);
+
+            QRegExp reg_exp(QString("(a?[ybnqiuxdtsogv]|a[{]sv[}])"));
+            if (reg_exp.match(type))
+            { return type; }
+
+            DOC_ERROR(QString("Unnamed complex D-Bus type \"%1\" found.").arg(type));
+        }
+
+        return QString();
+    }
+
+    QString getDBusType(const QString & type)
+    {
+        QString scoped_type = type;
+        if (!scoped_type.contains("::"))
+        { scoped_type = getCurrentScope(type); }
+
+        if (m_namedTypeMap.contains(scoped_type))
+        { return m_namedTypeMap[scoped_type]; }
+        else
+        { return type; }
+    }
+
+    void addNamedType(const QString type)
+    {
+        QString scoped_name(getCurrentScope());
+
+        if (m_namedTypeMap.contains(scoped_name))
+        {
+            DOC_ERROR(QString("Named type \"%1\" is already defined.").arg(scoped_name));
+            return;
+        }
+
+        m_namedTypeMap.insert(scoped_name, type);
+    }
+
+    QString getCurrentScope(const QString & type = QString())
+    {
+        QString scoped_name;
+        if (!m_scopeStack.isEmpty())
+        {
+            scoped_name = m_scopeStack.last()->scope->name;
+            scoped_name.append("::");
+        }
+        if (!type.isEmpty())
+        { scoped_name.append(type); }
+        else
+        { scoped_name = scoped_name.left(scoped_name.length() - 2); }
+
+        return scoped_name;
+    }
+
+    int indexOf(const QXmlAttributes & attributes, const QString & name,
+                 const QString & type = "CDATA", const bool mandatory = true)
+    {
+        const int idx(attributes.index(name));
+        if (idx < 0 || idx > attributes.length()) { return -1; }
+        if (attributes.type(idx) != type) { return -1; }
+        if (mandatory && attributes.value(idx).isEmpty()) { return -1; }
+
+        return idx;
+    }
+
+    Entry * createEntry()
+    {
+        Entry * entry = new Entry();
+
+        entry->protection = Public ;
+        entry->virt       = Normal;
+        entry->stat       = false;
+        entry->objc       = false;
+        entry->spec       = 0;
+
+        entry->fileName  = m_fileName;
+        entry->startLine = lineNumber();
+        entry->bodyLine = lineNumber();
+
+        entry->callGraph = false;
+        entry->callerGraph = false;
+
+        initGroupInfo(entry);
+
+        m_currentEntry = entry;
+
+        handleComment();
+
+        return entry;
+    }
+
+    void openScopes(Entry * object)
+    {
+        int cur_scope_separator_pos = 0;
+        int last_scope_separator_pos = 0;
+        while (0 <= (cur_scope_separator_pos = object->name.find("::", last_scope_separator_pos)))
+        {
+            QString scope = object->name.mid(last_scope_separator_pos,
+                                             cur_scope_separator_pos - last_scope_separator_pos);
+            last_scope_separator_pos = cur_scope_separator_pos + 2;
+
+            Entry * current_namespace = openNamespace(scope);
+
+            if (!m_scopeStack.isEmpty())
+            { m_scopeStack.last()->scope->addSubEntry(current_namespace); }
+
+            m_scopeStack.append(new ScopeData(current_namespace, m_scopeCount));
+        }
+
+        QString scoped_name(getCurrentScope());
+        if (!scoped_name.isEmpty())
+        { scoped_name.append("::"); }
+        scoped_name.append(object->name.mid(last_scope_separator_pos));
+
+        object->name = scoped_name;
+
+        if (!m_scopeStack.isEmpty())
+        { m_scopeStack.last()->scope->addSubEntry(object); }
+        m_scopeStack.append(new ScopeData(object, m_scopeCount));
+
+        ++m_scopeCount;
+    }
+
+    Entry * openNamespace(const QString & name)
+    {
+        Entry * current_namespace = createEntry();
+        QString scoped_name(getCurrentScope());
+        if (!scoped_name.isEmpty())
+        { scoped_name.append("::"); }
+        scoped_name.append(name);
+        current_namespace->name = scoped_name;
+        current_namespace->section = Entry::NAMESPACE_SEC;
+        current_namespace->type = "namespace" ;
+
+        return current_namespace;
+    }
+
+    void closeScopes()
+    {
+        const int current_scope_count(m_scopeStack.last()->count);
+
+        // Do not close the root scope.
+        if (current_scope_count == 0)
+        { return; }
+
+        while (current_scope_count == m_scopeStack.last()->count)
+        { m_scopeStack.removeLast(); }
+    }
+
+    ParserInterface * m_parser;
+
+    QXmlLocator m_locator;
+    QString m_currentNode; // Nodes can not be nested, no entry necessary.
+
+    struct ElementData
+    {
+        ElementData(const QString & e) :
+            element(e)
+        { }
+        ~ElementData() { }
+
+        QString element; //*< The element name
+        QString extensionPrefix; //*< The prefix used for our extension.
+        QString text; //*< The actual xml code.
+    };
+    QList<ElementData> m_elementStack;
+
+    Entry * m_currentEntry; // The currently open entry.
+
+    Entry * m_currentInterface; // Interfaces can not be nested.
+    Entry * m_currentMethod; // Methods can not be nested.
+    Argument * m_currentArgument; // Arguments can not be nested.
+    Entry * m_currentProperty; // Properties can not be nested.
+    Entry * m_currentEnum; // Enums can not be nested.
+    QList<Entry> m_namespaceStack;
+
+    struct StructData
+    {
+        StructData(Entry * e) : entry(e) { }
+        ~StructData() { }
+
+        QString type;
+        Entry * entry;
+    };
+    QList<StructData> m_structStack; // Structs can be nested.
+
+    struct ScopeData
+    {
+        ScopeData(Entry * s, int c) :
+            scope(s),
+            count(c)
+        { }
+        ~ScopeData() { }
+
+        Entry * scope;
+        QString extensionPrefix;
+        int count;
+    };
+    QList<ScopeData> m_scopeStack; // Scopes are nested.
+
+    QString m_fileName;
+
+    struct CommentData
+    {
+        CommentData(const QString & f, const int l, const QString & t) :
+            isJavaStyle(false),
+            isQtStyle(false),
+            line(l),
+            fileName(f)
+        {
+            isJavaStyle = t.startsWith(QChar('*'));
+            isQtStyle = t.startsWith(QChar('!'));
+            shouldIgnore = (!isJavaStyle && !isQtStyle);
+            associateWithPrevious = (t.at(1) == QChar('<'));
+            if (associateWithPrevious)
+            { text = t.mid(2); }
+            else
+            { text = t.mid(1); }
+        }
+        ~CommentData() { }
+
+        QString text;
+        bool isJavaStyle;
+        bool isQtStyle;
+        bool shouldIgnore;
+        bool associateWithPrevious;
+        int line;
+        QString fileName;
+    };
+    CommentData * m_currentComment;
+
+    int m_scopeCount; //*< unique scope id.
+
+    QString m_errorString;
+
+    QMap<QString, QString> m_namedTypeMap;
+};
+
+// -----------------------------------------------------------------------
+// DBusXMLScanner
+// -----------------------------------------------------------------------
+
+DBusXMLScanner::DBusXMLScanner()
+{ }
+
+DBusXMLScanner::~DBusXMLScanner()
+{ }
+
+void DBusXMLScanner::parseInput(const char * fileName,
+                                const char * /* fileBuf */,
+                                Entry * root)
+{
+    QFile inputFile(fileName);
+
+    QXmlInputSource inputSource(inputFile);
+    QXmlSimpleReader reader;
+
+    DBusXMLHandler handler(this, &reader, fileName, root);
+    reader.setContentHandler(&handler);
+    reader.setErrorHandler(&handler);
+    reader.setLexicalHandler(&handler);
+
+    groupEnterFile(fileName, 1);
+    handler.setSection();
+    reader.parse(inputSource);
+
+    if (handler.errorString())
+    { err("ERROR parsing XML: %s\n", handler.errorString().utf8().data()); }
+
+    groupLeaveFile(fileName, 1);
+}
+
+bool DBusXMLScanner::needsPreprocessing(const QCString & /* extension */)
+{ return (false); }
+
+void DBusXMLScanner::parseCode(CodeOutputInterface & /* codeOutIntf */,
+                               const char * /* scopeName */,
+                               const QCString & /* input */,
+                               bool /* isExampleBlock */,
+                               const char * /* exampleName */,
+                               FileDef * /* fileDef */,
+                               int /* startLine */,
+                               int /* endLine */,
+                               bool /* inlineFragment */,
+                               MemberDef * /* memberDef */)
+{ }
+
+void DBusXMLScanner::resetCodeParserState()
+{ }
+
+void DBusXMLScanner::parsePrototype(const char * /* text */)
+{ }
diff --git a/src/dbusxmlscanner.h b/src/dbusxmlscanner.h
new file mode 100644
index 0000000..3a4994e
--- /dev/null
+++ b/src/dbusxmlscanner.h
@@ -0,0 +1,57 @@
+/******************************************************************************
+ *
+ *
+ *
+ * Copyright (C) 2009 by Tobias Hunger <tobias@aquazul.com>
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation under the terms of the GNU General Public License is hereby
+ * granted. No representations are made about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied warranty.
+ * See the GNU General Public License for more details.
+ *
+ * Documents produced by Doxygen are derivative works derived from the
+ * input used in their production; they are not affected by this license.
+ *
+ */
+
+#ifndef SCANNER_DBUSXML_H
+#define SCANNER_DBUSXML_H
+
+#include "parserintf.h"
+
+/** \brief D-Bus XML parser.
+ *
+ *  This is the D-Bus XML parser for doxygen.
+ */
+class DBusXMLScanner : public ParserInterface
+{
+public:
+    DBusXMLScanner();
+    virtual ~DBusXMLScanner();
+    void parseInput(const char *fileName,
+                    const char *fileBuf,
+                    Entry *root);
+
+    bool needsPreprocessing(const QCString &extension);
+
+    void parseCode(CodeOutputInterface &codeOutIntf,
+                   const char *scopeName,
+                   const QCString &input,
+                   bool isExampleBlock,
+                   const char *exampleName=0,
+                   FileDef *fileDef=0,
+                   int startLine=-1,
+                   int endLine=-1,
+                   bool inlineFragment=FALSE,
+                   MemberDef *memberDef=0
+                  );
+
+    void resetCodeParserState();
+
+    void parsePrototype(const char *text);
+
+private:
+};
+
+#endif
diff --git a/src/docparser.h b/src/docparser.h
index 5ecfb4b..bb867b8 100644
--- a/src/docparser.h
+++ b/src/docparser.h
@@ -169,6 +169,7 @@ template<class T> class CompAccept
 {
   public:
     CompAccept() { m_children.setAutoDelete(TRUE); }
+    virtual ~CompAccept() {}
     void accept(T *obj, DocVisitor *v) 
     { 
       v->visitPre(obj); 
diff --git a/src/docsets.cpp b/src/docsets.cpp
index fe43791..76d7679 100644
--- a/src/docsets.cpp
+++ b/src/docsets.cpp
@@ -263,6 +263,7 @@ void DocSets::addIndexItem(const char *, const char *,
     case SrcLangExt_Python: lang="python"; break;     // Python
     case SrcLangExt_F90:    lang="fortran"; break;    // Fortran
     case SrcLangExt_VHDL:   lang="vhdl"; break;       // VHDL
+    case SrcLangExt_XML:    lang="xml"; break;        // DBUS XML
   }
 
   // determine scope
diff --git a/src/doxygen.cpp b/src/doxygen.cpp
index 81cb544..8b063f1 100644
--- a/src/doxygen.cpp
+++ b/src/doxygen.cpp
@@ -71,6 +71,7 @@
 #include "htags.h"
 #include "pyscanner.h"
 #include "fortranscanner.h"
+#include "dbusxmlscanner.h"
 #include "code.h"
 #include "objcache.h"
 #include "store.h"
@@ -122,7 +123,6 @@ QTextStream      Doxygen::tagFile;
 NamespaceDef    *Doxygen::globalScope = 0;
 QDict<RefList>  *Doxygen::xrefLists = new QDict<RefList>; // dictionary of cross-referenced item lists
 bool             Doxygen::parseSourcesNeeded = FALSE;
-double           Doxygen::sysElapsedTime = 0.0;
 QTime            Doxygen::runningTime;
 //SearchIndex *    Doxygen::searchIndex=0;
 QDict<DefinitionIntf> *Doxygen::symbolMap;
@@ -2924,10 +2924,23 @@ static void buildFunctionList(EntryNav *rootNav)
             //printf("matching arguments for %s%s %s%s\n",
             //    md->name().data(),md->argsString(),rname.data(),argListToString(root->argList).data());
             LockingPtr<ArgumentList> mdAl = md->argumentList();
+            LockingPtr<ArgumentList> mdTempl = md->templateArguments();
+
+            // in case of template functions, we need to check if the
+            // functions have the same number of template parameters
+            bool sameNumTemplateArgs = TRUE;
+            if (mdTempl!=0 && root->tArgLists)
+            {
+              if (mdTempl->count()!=root->tArgLists->getLast()->count())
+              {
+                sameNumTemplateArgs = FALSE;
+              }
+            }
             if ( 
                 matchArguments2(md->getOuterScope(),mfd,mdAl.pointer(),
                                 rnd ? rnd : Doxygen::globalScope,rfd,root->argList,
-                                FALSE)
+                                FALSE) &&
+                sameNumTemplateArgs
                )
             {
               GroupDef *gd=0;
@@ -4931,6 +4944,22 @@ static bool findGlobalMember(EntryNav *rootNav,
                           rnd ? rnd : Doxygen::globalScope,fd,root->argList,
                           FALSE);
 
+        // for template members we need to check if the number of
+        // template arguments is the same, otherwise we are dealing with
+        // different functions.
+        if (matching && root->tArgLists)
+        {
+          LockingPtr<ArgumentList> mdTempl = md->templateArguments();
+          if (mdTempl!=0)
+          {
+            if (root->tArgLists->getLast()->count()!=mdTempl->count())
+            {
+              matching=FALSE;
+            }
+          }
+        }
+
+
         //printf("%s<->%s\n",
         //    argListToString(md->argumentList()).data(),
         //    argListToString(root->argList).data());
@@ -6572,7 +6601,7 @@ static void addEnumValuesToEnums(EntryNav *rootNav)
               SrcLangExt sle;
               if (rootNav->fileDef() &&
                   ( (sle=getLanguageFromFileName(rootNav->fileDef()->name()))==SrcLangExt_CSharp
-                  || sle==SrcLangExt_Java
+                  || sle==SrcLangExt_Java || sle==SrcLangExt_XML
                   )
                  )
               {
@@ -9128,6 +9157,7 @@ void initDoxygen()
   Doxygen::parserManager->registerParser("python",  new PythonLanguageScanner);
   Doxygen::parserManager->registerParser("fortran", new FortranLanguageScanner);
   Doxygen::parserManager->registerParser("vhdl",    new VHDLLanguageScanner);
+  Doxygen::parserManager->registerParser("dbusxml", new DBusXMLScanner);
 
   // register any additional parsers here...
 
@@ -10539,7 +10569,7 @@ void generateOutput()
   {
     msg("Total elapsed time: %.3f seconds\n(of which %.3f seconds waiting for external tools to finish)\n",
          ((double)Doxygen::runningTime.elapsed())/1000.0,
-         Doxygen::sysElapsedTime
+         portable_getSysElapsedTime()
         );
   }
 
diff --git a/src/doxygen.h b/src/doxygen.h
index 1aee032..859f63c 100644
--- a/src/doxygen.h
+++ b/src/doxygen.h
@@ -111,7 +111,6 @@ class Doxygen
     static QDict<RefList>           *xrefLists; // array of xref lists: todo, test, bug, deprecated ...
     static QCString                  htmlFileExtension;
     static bool                      parseSourcesNeeded;
-    static double                    sysElapsedTime;
     static QTime                     runningTime;
     //static SearchIndex              *searchIndex;
     static QDict<DefinitionIntf>    *symbolMap;
diff --git a/src/fortranscanner.l b/src/fortranscanner.l
index 766a261..97909f0 100644
--- a/src/fortranscanner.l
+++ b/src/fortranscanner.l
@@ -171,7 +171,7 @@ static int yyread(char *buf,int max_size);
 static void startCommentBlock(bool);
 static void handleCommentBlock(const QCString &doc,bool brief);
 static void addCurrentEntry();
-static void addModule(const char *name);
+static void addModule(const char *name, bool isModule=FALSE);
 static void addSubprogram(const char *text);
 static void addInterface(QCString name);
 static Argument *addFortranParameter(const QCString &type,const QCString &name, const QCString docs);
@@ -242,6 +242,7 @@ PREFIX    (RECURSIVE{BS_}|PURE{BS_}|ELEMENTAL{BS_}){0,2}(RECURSIVE|PURE|ELEMENTA
 %x	Start
 %x	Comment
 %x      Module
+%x      Program
 %x      ModuleBody
 %x	ModuleBodyContains
 %x	AttributeList
@@ -437,7 +438,10 @@ PREFIX    (RECURSIVE{BS_}|PURE{BS_}|ELEMENTAL{BS_}){0,2}(RECURSIVE|PURE|ELEMENTA
 
  /*------ module handling ------------------------------------------------------------*/ 
 <Start>module|program{BS_}             {  //
-					    yy_push_state(Module);
+					    if(yytext[0]=='m' || yytext[0]=='M')
+					      yy_push_state(Module);
+					    else
+					      yy_push_state(Program);
                                             defaultProtection = Public;
                                        }
 <Start,ModuleBody,ModuleBodyContains>^{BS}"end"({BS}(module|program)({BS_}{ID})?)?{BS}/(\n|!) { // end module	
@@ -448,7 +452,12 @@ PREFIX    (RECURSIVE{BS_}|PURE{BS_}|ELEMENTAL{BS_}){0,2}(RECURSIVE|PURE|ELEMENTA
 					    yy_pop_state();
                                        }
 <Module>{ID}                           {  
-                                            addModule(yytext);
+                                            addModule(yytext, TRUE);
+					    BEGIN(ModuleBody);
+                                       }
+
+<Program>{ID}                           {  
+                                            addModule(yytext, FALSE);
 					    BEGIN(ModuleBody);
                                        }
 
@@ -1468,11 +1477,15 @@ static void addCurrentEntry()
 
 static int max(int a, int b) {return a>b?a:b;}
 
-static void addModule(const char *name)
+static void addModule(const char *name, bool isModule)
 {
   //fprintf(stderr, "0=========> got module %s\n", name);
 
-  current->section = Entry::NAMESPACE_SEC;
+  if (isModule)
+    current->section = Entry::NAMESPACE_SEC;
+  else
+    current->section = Entry::FUNCTION_SEC;
+
   if (name!=NULL)
   {
     current->name = name;
diff --git a/src/ftvhelp.cpp b/src/ftvhelp.cpp
index 285988a..3988c57 100644
--- a/src/ftvhelp.cpp
+++ b/src/ftvhelp.cpp
@@ -731,10 +731,12 @@ void FTVHelp::generateTreeView(QString* OutString)
       t << "      --></script>\n";
       t << "      <div id=\"MSearchBox\" class=\"MSearchBoxInactive\">\n";
       t << "      <div class=\"MSearchBoxRow\"><span class=\"MSearchBoxLeft\">\n";
-      t << "      <input type=\"text\" id=\"MSearchField\" value=\"Search\" \n";
+      t << "      <a id=\"MSearchClose\" href=\"javascript:searchBox.CloseResultsWindow()\">"
+        << "<img id=\"MSearchCloseImg\" border=\"0\" src=\"search/close.png\" alt=\"\"/></a>\n";
+      t << "      <input type=\"text\" id=\"MSearchField\" value=\"Search\" accesskey=\"S\"\n";
       t << "           onfocus=\"searchBox.OnSearchFieldFocus(true)\" \n";
       t << "           onblur=\"searchBox.OnSearchFieldFocus(false)\" \n";
-      t << "           onkeyup=\"searchBox.OnSearchFieldChange()\"/>\n";
+      t << "           onkeyup=\"searchBox.OnSearchFieldChange(event)\"/>\n";
       t << "      </span><span class=\"MSearchBoxRight\">\n";
       t << "      <img id=\"MSearchSelect\" src=\"search/search.png\"\n";
       t << "           onmouseover=\"return searchBox.OnSearchSelectShow()\"\n";
diff --git a/src/htmlgen.cpp b/src/htmlgen.cpp
index 0383f55..74bea86 100644
--- a/src/htmlgen.cpp
+++ b/src/htmlgen.cpp
@@ -399,91 +399,31 @@ static unsigned int search_png_len = 527;
 
 static unsigned char close_png[] = {
   0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
-  0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f,
-  0x08, 0x02, 0x00, 0x00, 0x00, 0x5b, 0x76, 0x69, 0x23, 0x00, 0x00, 0x01,
-  0xa0, 0x49, 0x44, 0x41, 0x54, 0x28, 0x15, 0x8d, 0x91, 0x3b, 0xaf, 0x01,
-  0x51, 0x14, 0x85, 0xef, 0x3c, 0x5c, 0x42, 0xbc, 0x49, 0xbc, 0x12, 0x8d,
-  0x02, 0x85, 0x76, 0x42, 0x49, 0xa3, 0x95, 0xe8, 0xfd, 0x1e, 0x9d, 0x9f,
-  0x20, 0x51, 0xf2, 0x13, 0x24, 0x3a, 0x85, 0x82, 0x4a, 0xa2, 0x20, 0x9a,
-  0x29, 0x86, 0x10, 0xef, 0x47, 0x98, 0xe1, 0x7e, 0x73, 0x8f, 0xea, 0x56,
-  0xf7, 0x24, 0x8e, 0x73, 0xd6, 0x59, 0x7b, 0xed, 0xb5, 0xf6, 0x48, 0xcd,
-  0x66, 0xf3, 0xeb, 0x7f, 0x4b, 0x95, 0x24, 0x49, 0x30, 0x5f, 0xaf, 0x97,
-  0xae, 0xeb, 0xeb, 0xf5, 0xfa, 0x74, 0x3a, 0x01, 0xfa, 0x7c, 0xbe, 0x68,
-  0x34, 0x9a, 0x4c, 0x26, 0x65, 0x59, 0x16, 0x84, 0x0f, 0xf5, 0x7e, 0xbf,
-  0x4f, 0x26, 0x93, 0xdb, 0xed, 0xa6, 0xaa, 0xaa, 0xcb, 0xe5, 0xe2, 0xf9,
-  0xf9, 0x7c, 0x52, 0xb9, 0xd9, 0x6c, 0xf2, 0xf9, 0x3c, 0x08, 0x6c, 0xbb,
-  0x02, 0xbd, 0xf1, 0x78, 0x0c, 0xbb, 0x58, 0x2c, 0xa2, 0xf4, 0xfd, 0xbb,
-  0x50, 0xd5, 0x34, 0xcd, 0x34, 0xcd, 0xd9, 0x6c, 0x06, 0x01, 0x9a, 0xca,
-  0x8f, 0x6a, 0x78, 0xa5, 0x52, 0xa9, 0x5c, 0x2e, 0x1f, 0x0e, 0x87, 0x6e,
-  0xb7, 0x0b, 0x58, 0xab, 0xd5, 0xc2, 0xe1, 0x30, 0xf2, 0xa3, 0xd1, 0x68,
-  0xb5, 0x5a, 0xc5, 0xe3, 0x71, 0xdb, 0x00, 0xfe, 0x1c, 0x0e, 0xc7, 0x72,
-  0xb9, 0x84, 0xe7, 0xf7, 0xfb, 0xeb, 0xf5, 0xba, 0x65, 0x59, 0xf0, 0x2e,
-  0x97, 0xcb, 0x74, 0x3a, 0x7d, 0xbf, 0xdf, 0xfb, 0xfd, 0x3e, 0x91, 0x48,
-  0xc8, 0x50, 0xc9, 0x81, 0x45, 0x8c, 0xf6, 0x7a, 0xbd, 0xe3, 0xf1, 0x18,
-  0x0c, 0x06, 0x23, 0x91, 0x08, 0xbc, 0x4e, 0xa7, 0xb3, 0xdd, 0x6e, 0x11,
-  0xa6, 0x27, 0x34, 0xdb, 0x2b, 0x7f, 0x8a, 0xa2, 0x00, 0x71, 0xc0, 0x1c,
-  0x08, 0x8b, 0x58, 0x8f, 0xc7, 0x03, 0xdb, 0xa8, 0xf0, 0x0a, 0x62, 0x3f,
-  0x87, 0x42, 0x21, 0x4e, 0xc4, 0x14, 0xfe, 0xce, 0xe7, 0x33, 0x4e, 0xd0,
-  0x6e, 0x34, 0x1a, 0x84, 0x83, 0xe0, 0xf5, 0x7a, 0xd9, 0x6d, 0x55, 0x86,
-  0x47, 0xc6, 0x5c, 0x2e, 0x47, 0x8d, 0xe8, 0xdb, 0x6e, 0xb7, 0xf1, 0x17,
-  0x08, 0x04, 0x0a, 0x85, 0x02, 0x7d, 0x18, 0x0b, 0x34, 0xa5, 0x5a, 0xad,
-  0x72, 0x32, 0x0c, 0x83, 0x39, 0x90, 0xa0, 0xdf, 0xef, 0xef, 0x76, 0x3b,
-  0xcc, 0xcc, 0xe7, 0x73, 0x3c, 0x0c, 0x06, 0x03, 0x0a, 0xb2, 0xd9, 0x2c,
-  0x05, 0x52, 0xab, 0xd5, 0xa2, 0xc2, 0xe3, 0xf1, 0x0c, 0x87, 0xc3, 0xeb,
-  0xf5, 0x8a, 0x3c, 0x3c, 0xfc, 0x01, 0x32, 0x07, 0xb7, 0xdb, 0xcd, 0x10,
-  0xb1, 0xc4, 0xd5, 0x86, 0x58, 0x64, 0xac, 0x54, 0x2a, 0x8b, 0xc5, 0x82,
-  0xc1, 0x09, 0x55, 0xc4, 0x62, 0xb1, 0x58, 0x3a, 0x9d, 0xe6, 0x2a, 0x38,
-  0x9f, 0x0f, 0x8b, 0x18, 0x73, 0x49, 0xa5, 0x52, 0x99, 0x4c, 0xc6, 0xe9,
-  0x74, 0xf2, 0x46, 0x7c, 0xc6, 0x07, 0xc8, 0x99, 0x4c, 0xec, 0x1f, 0x55,
-  0x51, 0x47, 0x23, 0xd1, 0x4b, 0x5c, 0xff, 0xec, 0x3f, 0x83, 0x85, 0xe4,
-  0x1a, 0x44, 0x83, 0x01, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e,
-  0x44, 0xae, 0x42, 0x60, 0x82
+  0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b,
+  0x08, 0x06, 0x00, 0x00, 0x00, 0xa9, 0xac, 0x77, 0x26, 0x00, 0x00, 0x00,
+  0xd8, 0x49, 0x44, 0x41, 0x54, 0x18, 0x19, 0x75, 0x51, 0xbd, 0x12, 0x46,
+  0x40, 0x0c, 0xdc, 0x18, 0x15, 0x0a, 0x14, 0x14, 0x1a, 0x43, 0xeb, 0x35,
+  0xbc, 0x7f, 0xa7, 0x43, 0x67, 0x06, 0x33, 0x28, 0xd0, 0xde, 0x77, 0x7b,
+  0x23, 0x2a, 0xdf, 0x16, 0x97, 0x9f, 0xdb, 0xcb, 0x26, 0x39, 0xc1, 0x83,
+  0x7d, 0xdf, 0xcd, 0xb2, 0x2c, 0xd8, 0xb6, 0x0d, 0xe7, 0x79, 0x22, 0x8a,
+  0x22, 0xc4, 0x71, 0x8c, 0x3c, 0xcf, 0x91, 0xa6, 0xa9, 0x90, 0xe6, 0x8e,
+  0x69, 0x9a, 0xcc, 0x38, 0x8e, 0xb8, 0xae, 0x4b, 0xdf, 0xbe, 0x36, 0x0c,
+  0x43, 0x94, 0x65, 0x89, 0xa2, 0x28, 0xc4, 0x3b, 0x8e, 0xe3, 0x2f, 0x91,
+  0x2f, 0xa8, 0xc2, 0x42, 0x56, 0xd1, 0x78, 0xf3, 0x3c, 0xbb, 0x04, 0x2f,
+  0xda, 0xb6, 0x45, 0x55, 0x55, 0x74, 0x9d, 0x65, 0x2c, 0x22, 0xb8, 0xef,
+  0x1b, 0xeb, 0xba, 0xc2, 0x67, 0x8f, 0x4c, 0x10, 0x7d, 0xdf, 0xa3, 0xae,
+  0x6b, 0xe7, 0xd3, 0x32, 0x56, 0x90, 0xe7, 0x53, 0x46, 0x31, 0x0c, 0x83,
+  0x73, 0x95, 0xa8, 0x31, 0x93, 0x9c, 0xc7, 0xe3, 0xd4, 0x0a, 0xb6, 0xa0,
+  0x44, 0x5a, 0xc6, 0xc6, 0x18, 0x77, 0xcd, 0x41, 0xbd, 0x24, 0x49, 0x94,
+  0xfb, 0x12, 0x59, 0x51, 0x5b, 0xd2, 0x16, 0xed, 0xfa, 0x20, 0xdc, 0x6f,
+  0xd7, 0x75, 0x9f, 0x6b, 0xd3, 0x2a, 0x41, 0x10, 0xa0, 0x69, 0x1a, 0x57,
+  0x59, 0x28, 0x47, 0x99, 0x2f, 0x30, 0xcf, 0x7b, 0xfb, 0x41, 0xcf, 0x1a,
+  0x2c, 0xeb, 0xeb, 0x07, 0x29, 0x9d, 0x65, 0x19, 0x6c, 0xab, 0x6e, 0x5d,
+  0x3f, 0x07, 0x0a, 0x79, 0x90, 0x0e, 0x11, 0x45, 0xc2, 0x00, 0x00, 0x00,
+  0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
 };
-static unsigned int close_png_len = 473;
+static unsigned int close_png_len = 273;
 
-static unsigned char close_active_png[] = {
-  0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
-  0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f,
-  0x08, 0x02, 0x00, 0x00, 0x00, 0x5b, 0x76, 0x69, 0x23, 0x00, 0x00, 0x01,
-  0xa0, 0x49, 0x44, 0x41, 0x54, 0x28, 0x15, 0x8d, 0x91, 0x3d, 0x8f, 0x01,
-  0x51, 0x14, 0x86, 0x77, 0x3e, 0xd6, 0x47, 0x22, 0xbe, 0x82, 0x10, 0x14,
-  0xa2, 0x21, 0x12, 0x09, 0x89, 0x0a, 0x85, 0x4a, 0x68, 0xf4, 0x12, 0x3f,
-  0x82, 0x52, 0xaf, 0x92, 0x68, 0x75, 0x5a, 0x7f, 0x41, 0x42, 0x47, 0xa3,
-  0xa0, 0x42, 0x68, 0x49, 0x44, 0x47, 0x10, 0xf1, 0x11, 0xec, 0x33, 0x7b,
-  0x67, 0xb7, 0xd8, 0x6a, 0x4f, 0x32, 0x33, 0x77, 0xee, 0x79, 0xce, 0x7b,
-  0xdf, 0x73, 0xae, 0xd4, 0xe9, 0x74, 0x3e, 0xfe, 0x17, 0xea, 0x2f, 0xf6,
-  0x7c, 0x3e, 0x17, 0x8b, 0xc5, 0x66, 0xb3, 0xd9, 0xef, 0xf7, 0x92, 0x24,
-  0x39, 0x9d, 0xce, 0x40, 0x20, 0x10, 0x8d, 0x46, 0x15, 0x45, 0x11, 0x8c,
-  0x8e, 0x9e, 0xcf, 0xe7, 0xc1, 0x60, 0xc0, 0x5b, 0x55, 0x55, 0xa3, 0xd1,
-  0x28, 0xcb, 0xf2, 0xe5, 0x72, 0x59, 0x2e, 0x97, 0x54, 0x66, 0xb3, 0x59,
-  0x8b, 0xc5, 0x02, 0x2d, 0xf3, 0xa0, 0xd7, 0xef, 0xf7, 0xc9, 0x55, 0x2a,
-  0x95, 0x70, 0x38, 0xfc, 0xf9, 0x1d, 0x7e, 0xbf, 0xbf, 0x5c, 0x2e, 0xdf,
-  0x6e, 0xb7, 0xd1, 0x68, 0x04, 0x00, 0xa6, 0x94, 0x4a, 0xa5, 0xf9, 0x7c,
-  0x4e, 0x35, 0x5c, 0xb1, 0x58, 0x4c, 0x26, 0x93, 0xb3, 0xd9, 0xcc, 0x6c,
-  0x36, 0xd7, 0x6a, 0xb5, 0x58, 0x2c, 0x66, 0xb5, 0x5a, 0x27, 0x93, 0x09,
-  0x1e, 0x5c, 0x2e, 0x97, 0x66, 0x60, 0xbd, 0x5e, 0x73, 0xee, 0x78, 0x3c,
-  0x4e, 0xa7, 0xd3, 0xe4, 0xaa, 0xd5, 0xea, 0xeb, 0xf5, 0x72, 0x38, 0x1c,
-  0x9c, 0x33, 0x1c, 0x0e, 0xdf, 0xef, 0xf7, 0x6e, 0xb7, 0x8b, 0x44, 0x22,
-  0x9a, 0x81, 0xc3, 0xe1, 0x00, 0xba, 0xdd, 0x6e, 0x5b, 0xad, 0xd6, 0xf1,
-  0x78, 0xb4, 0xd9, 0x6c, 0x82, 0x6b, 0x36, 0x9b, 0xd8, 0xa5, 0xc5, 0xd3,
-  0xe9, 0x04, 0xa6, 0xa1, 0x34, 0x21, 0x02, 0x4f, 0xc2, 0x16, 0x9b, 0x8f,
-  0xc7, 0x03, 0x55, 0x83, 0xc1, 0x80, 0x0a, 0xa1, 0xa3, 0x1e, 0x8f, 0x87,
-  0x15, 0x6f, 0xfc, 0x09, 0x3d, 0xa1, 0x5d, 0xaf, 0xd7, 0x83, 0xc1, 0x20,
-  0x29, 0x36, 0x75, 0x34, 0x14, 0x0a, 0x61, 0x2e, 0x97, 0xcb, 0xfd, 0x9e,
-  0xdb, 0x68, 0x34, 0x04, 0x9d, 0xcf, 0xe7, 0x39, 0x47, 0x14, 0x68, 0x13,
-  0xf0, 0x7a, 0xbd, 0x74, 0x36, 0x9d, 0x4e, 0xed, 0x76, 0x7b, 0xb7, 0xdb,
-  0x5d, 0xad, 0x56, 0xd7, 0xeb, 0x95, 0xb1, 0x30, 0xb4, 0x76, 0xbb, 0xed,
-  0x76, 0xbb, 0x53, 0xa9, 0x14, 0x05, 0x92, 0xb8, 0x58, 0xc6, 0xde, 0xeb,
-  0xf5, 0xb8, 0x27, 0xfa, 0xa5, 0x0f, 0x61, 0x8e, 0x34, 0xc5, 0x85, 0x42,
-  0x81, 0x4a, 0x0c, 0x68, 0xaa, 0x7c, 0x20, 0x12, 0x89, 0x84, 0xc9, 0x64,
-  0x62, 0x41, 0x37, 0x74, 0xe9, 0xf3, 0xf9, 0xe2, 0xf1, 0x78, 0x26, 0x93,
-  0xe1, 0x97, 0x4d, 0x18, 0xfd, 0x62, 0xf1, 0x8a, 0x24, 0x57, 0xc5, 0xd8,
-  0xe9, 0x9a, 0xc4, 0xfd, 0x7e, 0x47, 0x8c, 0x4d, 0xd6, 0x22, 0x74, 0x54,
-  0xfc, 0x20, 0x40, 0xfc, 0xa4, 0xfe, 0x7e, 0xbf, 0x00, 0xa8, 0x79, 0xe1,
-  0x90, 0xdb, 0x2c, 0x9e, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e,
-  0x44, 0xae, 0x42, 0x60, 0x82
-};
-static unsigned int close_active_png_len = 473;
 
 static const char tabs_css[] = 
 "/* tabs styles, based on http://www.alistapart.com/articles/slidingdoors */\n"
@@ -638,7 +578,6 @@ static img_data_item search_data[] =
 {
   { "search.png",       search_png,       search_png_len },
   { "close.png",        close_png,        close_png_len },
-  { "close_active.png", close_active_png, close_active_png_len },
   { 0, 0, 0 }
 };
 
@@ -894,21 +833,17 @@ void HtmlGenerator::startFile(const char *name,const char *,
 
 void HtmlGenerator::writeSearchFooter(QTextStream &t,const QCString &relPath)
 {
+  (void)relPath;
   t << "<!--- window showing the filter options -->\n";
   t << "<div id=\"MSearchSelectWindow\"\n";
   t << "     onmouseover=\"return searchBox.OnSearchSelectShow()\"\n";
-  t << "     onmouseout=\"return searchBox.OnSearchSelectHide()\">\n";
+  t << "     onmouseout=\"return searchBox.OnSearchSelectHide()\"\n";
+  t << "     onkeydown=\"return searchBox.OnSearchSelectKey(event)\">\n";
   writeSearchCategories(t);
   t << "</div>\n";
   t << "\n";
   t << "<!-- iframe showing the search results (closed by default) -->\n";
   t << "<div id=\"MSearchResultsWindow\">\n";
-  t << "<a href=\"javascript:searchBox.CloseResultsWindow()\" \n";
-  t << "   id=\"MSearchResultsWindowClose\"\n";
-  t << "   onmouseover=\"return searchBox.OnCloseHighlight(true)\"\n";
-  t << "   onmouseout=\"return searchBox.OnCloseHighlight(false)\">"
-    << "<img border=\"0\" src=\"" << relPath << "search/close.png\" "
-    << "alt=\"\"/></a>\n";
   t << "<iframe src=\"\" frameborder=\"0\" \n";
   t << "        name=\"MSearchResults\" id=\"MSearchResults\">\n";
   t << "</iframe>\n";
@@ -2092,10 +2027,12 @@ static void renderQuickLinksAsTabs(QTextStream &t,const QCString &relPath,
             t << "             onmouseover=\"return searchBox.OnSearchSelectShow()\"\n";
             t << "             onmouseout=\"return searchBox.OnSearchSelectHide()\"\n";
             t << "             alt=\"\"/>\n";
-            t << "        <input type=\"text\" id=\"MSearchField\" value=\"Search\" \n";
+            t << "        <input type=\"text\" id=\"MSearchField\" value=\"Search\" accesskey=\"S\"\n";
             t << "             onfocus=\"searchBox.OnSearchFieldFocus(true)\" \n";
             t << "             onblur=\"searchBox.OnSearchFieldFocus(false)\" \n";
-            t << "             onkeyup=\"searchBox.OnSearchFieldChange()\"/>\n";
+            t << "             onkeyup=\"searchBox.OnSearchFieldChange(event)\"/>\n";
+            t << "        <a id=\"MSearchClose\" href=\"javascript:searchBox.CloseResultsWindow()\">"
+              << "<img id=\"MSearchCloseImg\" border=\"0\" src=\"" << relPath << "search/close.png\" alt=\"\"/></a>\n";
             t << "        </div>\n";
             t << "      </li>\n";
         }
diff --git a/src/index.cpp b/src/index.cpp
index ae71d93..ff59003 100644
--- a/src/index.cpp
+++ b/src/index.cpp
@@ -2532,6 +2532,7 @@ void writeSearchIndex()
 
           SDict<QList<Definition> >::Iterator li(g_searchIndexSymbols[i][p]);
           QList<Definition> *dl;
+          int itemCount=0;
           for (li.toFirst();(dl=li.current());++li)
           {
             Definition *d = dl->first();
@@ -2544,8 +2545,18 @@ void writeSearchIndex()
               MemberDef  *md   = 0;
               bool isMemberDef = d->definitionType()==Definition::TypeMember;
               if (isMemberDef) md = (MemberDef*)d;
-              t << "  <a class=\"SRSymbol\" href=\"../" << 
-                d->getOutputFileBase() << Doxygen::htmlFileExtension;
+              t << "  <a id=\"Item" << itemCount << "\" "
+                << "onkeydown=\""
+                << "return searchResults.Nav(event," << itemCount << ")\" "
+                << "onkeypress=\""
+                << "return searchResults.Nav(event," << itemCount << ")\" "
+                << "onkeyup=\""
+                << "return searchResults.Nav(event," << itemCount << ")\" "
+              //  << "onkeydown=\"return true\" "
+              //  << "onkeypress=\""
+              //  << "return searchResults.Nav(event," << itemCount << ")\" "
+                << "class=\"SRSymbol\" href=\"../" 
+                << d->getOutputFileBase() << Doxygen::htmlFileExtension;
               if (isMemberDef)
               {
                 t << "#" << ((MemberDef *)d)->anchor();
@@ -2575,7 +2586,18 @@ void writeSearchIndex()
             }
             else // multiple items with the same name
             {
-              t << "  <a class=\"SRSymbol\" href=\"javascript:searchResults.Toggle('SR_"
+              t << "  <a id=\"Item" << itemCount << "\" "
+                << "onkeydown=\""
+                << "return searchResults.Nav(event," << itemCount << ")\" "
+                << "onkeypress=\""
+                << "return searchResults.Nav(event," << itemCount << ")\" "
+                << "onkeyup=\""
+                << "return searchResults.Nav(event," << itemCount << ")\" "
+              //  << "onkeydown=\"return true\" "
+              //  << "onkeypress=\""
+              //  << "return searchResults.Nav(event," << itemCount << ")\" "
+                << "class=\"SRSymbol\" "
+                << "href=\"javascript:searchResults.Toggle('SR_"
                 << searchId(d->localName()) << "')\">" 
                 << convertToXML(d->localName()) << "</a>" << endl;
               t << "  <div class=\"SRChildren\">" << endl;
@@ -2583,6 +2605,7 @@ void writeSearchIndex()
               QListIterator<Definition> di(*dl);
               bool overloadedFunction = FALSE;
               Definition *prevScope = 0;
+              int childCount=0;
               for (di.toFirst();(d=di.current());)
               {
                 ++di;
@@ -2594,7 +2617,22 @@ void writeSearchIndex()
                 if (isMemberDef) md = (MemberDef*)d;
                 if (next) nextScope = next->getOuterScope();
 
-                t << "    <a class=\"SRScope\" href=\"../" << 
+                t << "    <a id=\"Item" << itemCount << "_c" 
+                  << childCount << "\" "
+                  << "onkeydown=\""
+                  << "return searchResults.NavChild(event," 
+                  << itemCount << "," << childCount << ")\" "
+                  << "onkeypress=\""
+                  << "return searchResults.NavChild(event," 
+                  << itemCount << "," << childCount << ")\" "
+                  << "onkeyup=\""
+                  << "return searchResults.NavChild(event," 
+                  << itemCount << "," << childCount << ")\" "
+                //  << "onkeydown=\"return true\" "
+                //  << "onkeypress=\""
+                //  << "return searchResults.NavChild(event," 
+                //  << itemCount << "," << childCount << ")\" "
+                  << "class=\"SRScope\" href=\"../" << 
                   d->getOutputFileBase() << Doxygen::htmlFileExtension;
                 if (isMemberDef)
                 {
@@ -2663,11 +2701,13 @@ void writeSearchIndex()
                 }
                 t << "</a>" << endl;
                 prevScope = scope;
+                childCount++;
               }
               t << "  </div>" << endl; // SRChildren
             }
             t << " </div>" << endl; // SREntry
             t << "</div>" << endl; // SRResult
+            itemCount++;
           }
           // TODO: translate "Searching"
           t << "<div class=\"SRStatus\" id=\"Searching\">Searching...</div>" << endl;
@@ -2709,23 +2749,40 @@ void writeSearchIndex()
       t << "var indexSectionsWithContent =" << endl;
       t << "{" << endl;
       bool first=TRUE;
+      int j=0;
       for (i=0;i<NUM_SEARCH_INDICES;i++)
       {
         if (g_searchIndexCount[i]>0)
         {
           if (!first) t << "," << endl;
-          t << "  \"" << g_searchIndexName[i] << "\": \"";
+          t << "  " << j << ": \"";
           for (p=32;p<MEMBER_INDEX_ENTRIES;p++)
           {
             t << (g_searchIndexSymbols[i][p].count()>0 ? "1" : "0");
           }
           t << "\"";
           first=FALSE;
+          j++;
+        }
+      }
+      if (!first) t << "\n";
+      t << "};" << endl << endl;
+      t << "var indexSectionNames =" << endl;
+      t << "{" << endl;
+      first=TRUE;
+      j=0;
+      for (i=0;i<NUM_SEARCH_INDICES;i++)
+      {
+        if (g_searchIndexCount[i]>0)
+        {
+          if (!first) t << "," << endl;
+          t << "  " << j << ": \"" << g_searchIndexName[i] << "\"";
+          first=FALSE;
+          j++;
         }
       }
       if (!first) t << "\n";
       t << "};" << endl << endl;
-
       t << search_script;
     }
   }
@@ -2768,8 +2825,7 @@ void writeSearchCategories(QTextStream &t)
     if (g_searchIndexCount[i]>0)
     {
       t << "<a class=\"SelectItem\" href=\"javascript:void(0)\" "
-        << "onclick=\"searchBox.OnSelectItem(" << j << ",'" 
-        << g_searchIndexName[i] << "')\">"
+        << "onclick=\"searchBox.OnSelectItem(" << j << ")\">"
         << "<span class=\"SelectionMark\">&nbsp;</span>"
         << convertToXML(map.categoryLabel[i])
         << "</a>";
diff --git a/src/latexgen.cpp b/src/latexgen.cpp
index 37a3454..b76c7e2 100644
--- a/src/latexgen.cpp
+++ b/src/latexgen.cpp
@@ -793,9 +793,9 @@ void LatexGenerator::endIndexSection(IndexSections is)
               if (isFirst)
               {
                 t << "}\n\\input{" << fd->getOutputFileBase() << "}\n";
-                if (sourceBrowser && m_prettyCode)
+                if (sourceBrowser && m_prettyCode && fd->generateSourceFile())
                 {
-                  t << "\\input{" << fd->getSourceFileBase() << "}\n";
+                  t << "\\include{" << fd->getSourceFileBase() << "}\n";
                 }
                 isFirst=FALSE;
               }
@@ -803,10 +803,9 @@ void LatexGenerator::endIndexSection(IndexSections is)
               {
                 if (compactLatex) t << "\\input" ; else t << "\\include";
                 t << "{" << fd->getOutputFileBase() << "}\n";
-                if (sourceBrowser && m_prettyCode)
+                if (sourceBrowser && m_prettyCode && fd->generateSourceFile())
                 {
-                  if (compactLatex) t << "\\input" ; else t << "\\include";
-                  t << "{" << fd->getSourceFileBase() << "}\n";
+                  t << "\\include{" << fd->getSourceFileBase() << "}\n";
                 }
               }
             }
diff --git a/src/libdoxygen.pro.in b/src/libdoxygen.pro.in
index d66fed1..12711d1 100644
--- a/src/libdoxygen.pro.in
+++ b/src/libdoxygen.pro.in
@@ -88,6 +88,7 @@ HEADERS      =	bufstr.h \
                 pyscanner.h \
                 fortrancode.h \
                 fortranscanner.h \
+                dbusxmlscanner.h \
 		qhp.h \
 		qhpxmlwriter.h \
 		qtbc.h \
@@ -231,6 +232,7 @@ SOURCES      =	ce_lex.cpp \
 		vhdlscanner.cpp \
 		xmldocvisitor.cpp \
                 xmlgen.cpp \
+                dbusxmlscanner.cpp \
 
 win32:TMAKE_CXXFLAGS       += -DQT_NODLL 
 win32-msvc:TMAKE_CXXFLAGS  += -Zm200
diff --git a/src/portable.cpp b/src/portable.cpp
index 0107f2c..17a65d8 100644
--- a/src/portable.cpp
+++ b/src/portable.cpp
@@ -368,3 +368,8 @@ int portable_pclose(FILE *stream)
   return pclose(stream);
 }
 
+double portable_getSysElapsedTime()
+{
+  return sysElapsedTime;
+}
+
diff --git a/src/portable.h b/src/portable.h
index 3745d66..0718932 100644
--- a/src/portable.h
+++ b/src/portable.h
@@ -28,6 +28,7 @@ const char *   portable_commandExtension();
 bool           portable_fileSystemIsCaseSensitive();
 FILE *         portable_popen(const char *name,const char *type);
 int            portable_pclose(FILE *stream);
+double         portable_getSysElapsedTime();
 
 extern "C" {
   void *         portable_iconv_open(const char* tocode, const char* fromcode);
diff --git a/src/pre.l b/src/pre.l
index c818ce9..83f5c9f 100644
--- a/src/pre.l
+++ b/src/pre.l
@@ -104,6 +104,7 @@ static QCString           g_blockName;
 static int                g_condCtx;
 static bool               g_skip;
 static QStack<bool>       g_condStack;
+static bool               g_insideCS; // C# has simpler preprocessor
 
 static bool               g_lexInit = FALSE;
 
@@ -118,6 +119,7 @@ static void setFileName(const char *name)
   g_yyFileName=convertToQCString(fi.absFilePath());
   g_yyFileDef=findFileDef(Doxygen::inputNameDict,g_yyFileName,ambig);
   if (g_yyFileDef && g_yyFileDef->isReference()) g_yyFileDef=0;
+  g_insideCS = g_yyFileName.right(3)==".cs";
 }
 
 static void incrLevel()
@@ -1817,7 +1819,7 @@ CHARLIT   (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
 					  g_insideComment=FALSE;
 					  BEGIN(DefineText); 
   					}
-<DefName>{ID}/{B}*"\n"			{
+<DefName>{ID}/{B}*"\n"			{ // bare define
   					  g_argDict = 0;
 					  g_defArgs = -1;
 					  g_defName = yytext;
@@ -1831,6 +1833,7 @@ CHARLIT   (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
 					    outputArray(tmp.data(),tmp.length());
 					    g_quoteArg=FALSE;
 					    g_insideComment=FALSE;
+					    if (g_insideCS) g_defText="1"; // for C#, use "1" as define text
 					    BEGIN(DefineText);
 					  }
 					  else // define is a guard => hide
diff --git a/src/scanner.l b/src/scanner.l
index 7862507..c6db28c 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -1713,6 +1713,7 @@ TYPEDEFPREFIX (("typedef"{BN}+)?)((("volatile"|"const"){BN}+)?)
 					}
 <FindMemberName>{SCOPENAME}{BN}*/"<"	{
   					  sharpCount=0;
+					  roundCount=0;
 					  lineCount();
   					  current->name+=((QCString)yytext).stripWhiteSpace();
 					  //current->memberSpec.resize(0);
@@ -1722,7 +1723,7 @@ TYPEDEFPREFIX (("typedef"{BN}+)?)((("volatile"|"const"){BN}+)?)
 					  else
 					    BEGIN( EndTemplate );
   					}
-<EndTemplate>"<<"			{
+<ClassTemplSpec,EndTemplate>"<<"	{
   					  current->name+=yytext;
   					  // *currentTemplateSpec+=yytext; 
   					}
@@ -1731,8 +1732,8 @@ TYPEDEFPREFIX (("typedef"{BN}+)?)((("volatile"|"const"){BN}+)?)
   					  // *currentTemplateSpec+='<'; 
 					  sharpCount++; 
 					}
-<EndTemplate>">>"			{
-  					  if (insideJava || insideCS || insideCli)
+<ClassTemplSpec,EndTemplate>">>"	{
+  					  if (insideJava || insideCS || insideCli || roundCount==0)
 					  {
 					    unput('>');
 					    unput(' ');
@@ -1781,6 +1782,12 @@ TYPEDEFPREFIX (("typedef"{BN}+)?)((("volatile"|"const"){BN}+)?)
 					    BEGIN(FindMemberName);
 					  }
   					}
+<ClassTemplSpec,EndTemplate>"("         { current->name+=*yytext;
+                                          roundCount++; 
+                                        }
+<ClassTemplSpec,EndTemplate>")"         { current->name+=*yytext;
+                                          if (roundCount>0) roundCount--; 
+                                        }
 <EndTemplate>.				{ 
   					  current->name+=*yytext;
   					  // *currentTemplateSpec+=*yytext; 
@@ -4132,7 +4139,7 @@ TYPEDEFPREFIX (("typedef"{BN}+)?)((("volatile"|"const"){BN}+)?)
 					      current->doc.resize(0);
 					    }
 #endif
-					    if (current->sli) // copy special list items
+					    if (current->sli && previous) // copy special list items
 					    {
 					      QListIterator<ListItemInfo> li(*current->sli);
 					      ListItemInfo *lii;
@@ -4315,6 +4322,7 @@ TYPEDEFPREFIX (("typedef"{BN}+)?)((("volatile"|"const"){BN}+)?)
 					  }
 					  else // C++ template specialization
 					  {
+					    roundCount=0;
 					    BEGIN( ClassTemplSpec );
 					  }
 					}
@@ -4770,9 +4778,22 @@ TYPEDEFPREFIX (("typedef"{BN}+)?)((("volatile"|"const"){BN}+)?)
 					  {
 					    REJECT;
 					  }
-					  else // for C++ >> is a bitshift operator and > > would end a nested template
+					  else // for C++ >> is a bitshift 
+					       // operator and > > would end 
+					       // a nested template.
+					       // We require the bitshift to be enclosed in braces.
+					       // See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1757.html
 					  {
-                                            *specName += yytext; 
+					    if (roundCount>0)
+					    {
+                                              *specName += yytext; 
+					    }
+					    else
+					    {
+  					      unput('>');
+  					      unput(' ');
+  					      unput('>');
+					    }
 					  }
                                         }
 <Specialization>"typename"{BN}+		{ lineCount(); }
diff --git a/src/search.css b/src/search.css
index 7f316ab..0ef06d9 100644
--- a/src/search.css
+++ b/src/search.css
@@ -17,11 +17,12 @@
     color: #999999;
     background-color: #FFFFFF;
     font-style: normal;
-    cursor: pointer;
+    cursor: text;
     padding: 0px 1px;
     margin: 0px 6px 0px 0px;
     border: none;
     outline: none;
+    vertical-align: middle;
 }
 #MSearchBox.MSearchBoxInactive:hover #MSearchField {
     background-color: #FFFFFF;
@@ -41,14 +42,26 @@
     display : inline;
     background : none;
     font: 9pt Verdana, sans-serif;
-    margin-right: -6px;
-    padding: 0;
     border: none;
     margin: 0px 0px 0px 6px;
-    vertical-align: bottom;
+    vertical-align: middle;
+    padding: 0px 0px;
+}
+
+#MSearchClose {
+    float : none;
+    display : none;
+    background : none;
+    border: none;
+    margin: 0px 4px 0px 0px;
     padding: 0px 0px;
-    background-color: #84B0C7;
+    outline: none;
+}
+
+#MSearchCloseImg {
+    vertical-align: middle;
 }
+
 .MSearchBoxLeft {
     display: block;
     text-align: left;
@@ -108,7 +121,7 @@ a.SelectItem {
     padding-left:   6px;
     padding-right: 12px;
 }
-a.SelectItem:visited,
+a.SelectItem:focus,
 a.SelectItem:active {
     color: #000000; 
     outline-style: none;
@@ -136,26 +149,6 @@ iframe#MSearchResults {
     border: 1px solid #000000;
     background-color: #EEF3F5;
     }
-#MSearchResultsWindowClose {
-    font-weight: bold;
-    font-size: 8pt;
-    display: block;
-    padding: 0px;
-    margin: 0px;
-    text-align: right;
-    text-decoration: none;
-    outline-style: none;
-    }
-#MSearchResultsWindowClose:link,
-#MSearchResultsWindowClose:visited {
-    color: #8A8A8A;
-    background-color: #8A8A8A;
-    }
-#MSearchResultsWindowClose:active,
-#MSearchResultsWindowClose:hover {
-    color: #9E9E9E;
-    background-color: #9E9E9E;
-    }
 
 /* ----------------------------------- */
 
@@ -198,6 +191,11 @@ a.SRScope {
     outline: none;
 }
 
+a.SRSymbol:focus, a.SRSymbol:active,
+a.SRScope:focus, a.SRScope:active {
+    text-decoration: underline;
+}
+
 .SRPage .SRStatus {
     padding: 2px 5px;
     font-size: 8pt;
diff --git a/src/search.js b/src/search.js
index 02af28d..7f81e57 100644
--- a/src/search.js
+++ b/src/search.js
@@ -69,7 +69,7 @@ function SearchBox(name, resultsPath, inFrame)
   this.lastSearchValue       = "";
   this.lastResultsPage       = "";
   this.hideTimeout           = 0;
-  this.searchTopic           = "all";
+  this.searchIndex           = 0;
   this.searchActive          = false;
   this.insideFrame           = inFrame;
 
@@ -90,8 +90,8 @@ function SearchBox(name, resultsPath, inFrame)
   this.DOMPopupSearchResultsWindow = function()
   {  return document.getElementById("MSearchResultsWindow");  }
 
-  this.DOMSearchResultWindowClose = function()
-  {  return document.getElementById("MSearchResultsWindowClose"); }
+  this.DOMSearchClose = function()
+  {  return document.getElementById("MSearchClose"); }
 
   this.DOMSearchBox = function()
   {  return document.getElementById("MSearchBox");  }
@@ -150,7 +150,7 @@ function SearchBox(name, resultsPath, inFrame)
   }
 
   // Called when the content of the search field is changed.
-  this.OnSearchFieldChange = function()
+  this.OnSearchFieldChange = function(evt)
   {
     if (this.keyTimeout) // kill running timer
     {
@@ -158,6 +158,40 @@ function SearchBox(name, resultsPath, inFrame)
       this.keyTimeout = 0;
     }
 
+    var e  = (evt) ? evt : window.event; // for IE
+    if (e.keyCode==40 || e.keyCode==13)
+    {
+      if (e.shiftKey==1)
+      {
+        this.OnSearchSelectShow();
+        var win=this.DOMSearchSelectWindow(); 
+        for (i=0;i<win.childNodes.length;i++)
+        {
+          var child = win.childNodes[i]; // get span within a
+          if (child.className=='SelectItem')
+          {
+            child.focus();
+            return;
+          }
+        }
+        return;
+      }
+      else if (window.frames.MSearchResults.searchResults)
+      {
+        var elem = window.frames.MSearchResults.searchResults.NavNext(0);
+        if (elem) elem.focus();
+      }
+    }
+    else if (e.keyCode==27) // Escape out of the search field
+    {
+      this.DOMSearchField().blur();
+      this.DOMPopupSearchResultsWindow().style.display = 'none';
+      this.DOMSearchClose().style.display = 'none';
+      this.lastSearchValue = '';
+      this.Activate(false);
+      return;
+    }
+
     // strip whitespaces
     var searchValue = this.DOMSearchField().value.replace(/ +/g, "");
 
@@ -172,14 +206,28 @@ function SearchBox(name, resultsPath, inFrame)
       else // empty search field
       {
         this.DOMPopupSearchResultsWindow().style.display = 'none';
+        this.DOMSearchClose().style.display = 'none';
         this.lastSearchValue = '';
       }
     }
   }
 
-  // Called when an search filter selection is made.
-  // set item with index id as the active item
-  this.OnSelectItem = function(id,topic)
+  this.SelectItemCount = function(id)
+  {
+    var count=0;
+    var win=this.DOMSearchSelectWindow(); 
+    for (i=0;i<win.childNodes.length;i++)
+    {
+      var child = win.childNodes[i]; // get span within a
+      if (child.className=='SelectItem')
+      {
+        count++;
+      }
+    }
+    return count;
+  }
+
+  this.SelectItemSet = function(id)
   {
     var i,j=0;
     var win=this.DOMSearchSelectWindow(); 
@@ -191,7 +239,6 @@ function SearchBox(name, resultsPath, inFrame)
         var node = child.firstChild;
 	if (j==id)
 	{
-          // add a tickmark: see http://doogalbellend.blogspot.com/2007/05/even-more-on-tick-marks-in-html.html
           node.innerHTML='&bull;';
         } 
         else
@@ -201,31 +248,39 @@ function SearchBox(name, resultsPath, inFrame)
         j++;
       }
     }
-    if (topic)
-    {
-      this.searchTopic = topic;
-      var searchValue = this.DOMSearchField().value.replace(/ +/g, "");
-      if (searchValue != "" && this.searchActive) // something was found -> do a search
-      {
-        this.Search();
-      }
-    }
-    else
+  }
+
+  // Called when an search filter selection is made.
+  // set item with index id as the active item
+  this.OnSelectItem = function(id)
+  {
+    this.searchIndex = id;
+    this.SelectItemSet(id);
+    var searchValue = this.DOMSearchField().value.replace(/ +/g, "");
+    if (searchValue!="" && this.searchActive) // something was found -> do a search
     {
-      this.Activate(false);
+      this.Search();
     }
   }
 
-  this.OnCloseHighlight = function(active)
+  this.OnSearchSelectKey = function(evt)
   {
-    var close = this.DOMSearchResultWindowClose();
-    if (active)
+    var e = (evt) ? evt : window.event; // for IE
+    if (e.keyCode==40 && this.searchIndex<this.SelectItemCount()) // Down
     {
-      close.firstChild.src = this.resultsPath + '/close_active.png';
+      this.searchIndex++;
+      this.OnSelectItem(this.searchIndex);
     }
-    else
+    else if (e.keyCode==38 && this.searchIndex>0) // Up
+    {
+      this.searchIndex--;
+      this.OnSelectItem(this.searchIndex);
+    }
+    else if (e.keyCode==13 || e.keyCode==27)
     {
-      close.firstChild.src = this.resultsPath + '/close.png';
+      this.OnSelectItem(this.searchIndex);
+      this.CloseSelectionWindow();
+      this.DOMSearchField().focus();
     }
     return false;
   }
@@ -235,13 +290,14 @@ function SearchBox(name, resultsPath, inFrame)
   // Closes the results window.
   this.CloseResultsWindow = function()
   {
-    this.DOMPopupSearchResultsWindow().style.display = "none";
+    this.DOMPopupSearchResultsWindow().style.display = 'none';
+    this.DOMSearchClose().style.display = 'none';
     this.Activate(false);
   }
 
   this.CloseSelectionWindow = function()
   {
-    this.DOMSearchSelectWindow().style.display = "none";
+    this.DOMSearchSelectWindow().style.display = 'none';
   }
 
   // Performs a search.
@@ -267,10 +323,9 @@ function SearchBox(name, resultsPath, inFrame)
     var resultsPageWithSearch;
     var hasResultsPage;
 
-    // indexSectionsWithContent is defined in searchdata.js
-    if (indexSectionsWithContent[this.searchTopic].charAt(code-32) == '1')
+    if (indexSectionsWithContent[this.searchIndex].charAt(code-32) == '1')
     {
-       resultsPage = this.resultsPath + '/' + this.searchTopic + '_' + hexCode + '.html';
+       resultsPage = this.resultsPath + '/' + indexSectionNames[this.searchIndex] + '_' + hexCode + '.html';
        resultsPageWithSearch = resultsPage+'?'+escape(searchValue);
        hasResultsPage = true;
     }
@@ -284,13 +339,13 @@ function SearchBox(name, resultsPath, inFrame)
     window.frames.MSearchResults.location.href = resultsPageWithSearch;  
     var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow();
 
-    if (domPopupSearchResultsWindow.style.display!="block")
+    if (domPopupSearchResultsWindow.style.display!='block')
     {
+       var domSearchBox = this.DOMSearchBox();
+       this.DOMSearchClose().style.display = 'inline';
        if (this.insideFrame)
        {
-         var domSearchBox = this.DOMSearchBox();
          var domPopupSearchResults = this.DOMPopupSearchResults();
-         this.DOMSearchResultWindowClose().style.textAlign = 'left';
          domPopupSearchResultsWindow.style.position = 'relative';
          domPopupSearchResultsWindow.style.display  = 'block';
          var width = document.body.clientWidth - 8; // the -8 is for IE :-(
@@ -299,10 +354,9 @@ function SearchBox(name, resultsPath, inFrame)
        }
        else
        {
-         var domSearchField = this.DOMSearchField();
          var domPopupSearchResults = this.DOMPopupSearchResults();
-         var left = getXPos(domSearchField) + domSearchField.offsetWidth;
-         var top  = getYPos(domSearchField) + domSearchField.offsetHeight + 1;
+         var left = getXPos(domSearchBox) + domSearchBox.offsetWidth;
+         var top  = getYPos(domSearchBox) + domSearchBox.offsetHeight + 1;
          domPopupSearchResultsWindow.style.display = 'block';
          left -= domPopupSearchResults.offsetWidth;
          domPopupSearchResultsWindow.style.top     = top  + 'px';
@@ -352,9 +406,11 @@ function SearchResults(name)
 {
     // The number of matches from the last run of <Search()>.
     this.lastMatchCount = 0;
+    this.lastKey = 0;
+    this.repeatOn = false;
 
     // Toggles the visibility of the passed element ID.
-    this.Toggle = function(id)
+    this.FindChildElement = function(id)
     {
       var parentElement = document.getElementById(id);
       var element = parentElement.firstChild;
@@ -363,14 +419,7 @@ function SearchResults(name)
       {
         if (element.nodeName == 'DIV' && element.className == 'SRChildren')
         {
-          if (element.style.display == 'block')
-          {  
-            element.style.display = 'none';  
-          }
-          else
-          {  
-            element.style.display = 'block';  
-          }
+          return element;
         }
 
         if (element.nodeName == 'DIV' && element.hasChildNodes())
@@ -397,6 +446,22 @@ function SearchResults(name)
       }
     }
 
+    this.Toggle = function(id)
+    {
+      var element = this.FindChildElement(id);
+      if (element)
+      {
+        if (element.style.display == 'block')
+        {  
+          element.style.display = 'none';  
+        }
+        else
+        {  
+          element.style.display = 'block';  
+        }
+      }
+    }
+
     // Searches for the passed string.  If there is no parameter, 
     // it takes it from the URL query.
     //
@@ -431,26 +496,213 @@ function SearchResults(name)
           if (search.length<=rowMatchName.length && 
              rowMatchName.substr(0, search.length)==search)
           {
-            row.style.display = "block";
+            row.style.display = 'block';
             matches++;
           }
           else
           {  
-            row.style.display = "none";  
+            row.style.display = 'none';  
           }
         }
         i++;
       }
-      document.getElementById("Searching").style.display="none";
+      document.getElementById("Searching").style.display='none';
       if (matches == 0) // no results
       {  
-        document.getElementById("NoMatches").style.display="block";  
+        document.getElementById("NoMatches").style.display='block';  
       }
       else // at least one result
       {  
-        document.getElementById("NoMatches").style.display="none";  
+        document.getElementById("NoMatches").style.display='none';  
       }
       this.lastMatchCount = matches;
       return true;
     }
+
+    // return the first item with index index or higher that is visible
+    this.NavNext = function(index)
+    {
+      var focusItem;
+      while (1)
+      {
+        var focusName = 'Item'+index;
+        focusItem = document.getElementById(focusName);
+        if (focusItem && focusItem.parentNode.parentNode.style.display=='block')
+        {
+          break;
+        }
+        else if (!focusItem) // last element
+        {
+          break;
+        }
+        focusItem=null;
+        index++;
+      }
+      return focusItem;
+    }
+
+    this.NavPrev = function(index)
+    {
+      var focusItem;
+      while (1)
+      {
+        var focusName = 'Item'+index;
+        focusItem = document.getElementById(focusName);
+        if (focusItem && focusItem.parentNode.parentNode.style.display=='block')
+        {
+          break;
+        }
+        else if (!focusItem) // last element
+        {
+          break;
+        }
+        focusItem=null;
+        index--;
+      }
+      return focusItem;
+    }
+
+    this.ProcessKeys = function(e)
+    {
+      if (e.type == "keydown") 
+      {
+        this.repeatOn = false;
+        this.lastKey = e.keyCode;
+      }
+      else if (e.type == "keypress")
+      {
+        if (!this.repeatOn)
+        {
+          if (this.lastKey) this.repeatOn = true;
+          return false; // ignore first keypress after keydown
+        }
+      }
+      else if (e.type == "keyup")
+      {
+        this.lastKey = 0;
+        this.repeatOn = false;
+      }
+      return this.lastKey!=0;
+    }
+
+    this.Nav = function(evt,itemIndex) 
+    {
+      var e  = (evt) ? evt : window.event; // for IE
+      if (e.keyCode==13) return true;
+      if (!this.ProcessKeys(e)) return false;
+
+      if (this.lastKey==38) // Up
+      {
+        var newIndex = itemIndex-1;
+        var focusItem = this.NavPrev(newIndex);
+        if (focusItem)
+        {
+          var child = this.FindChildElement(focusItem.parentNode.parentNode.id);
+          if (child && child.style.display == 'block') // children visible
+          { 
+            var n=0;
+            var tmpElem;
+            while (1) // search for last child
+            {
+              tmpElem = document.getElementById('Item'+newIndex+'_c'+n);
+              if (tmpElem) 
+              {
+                focusItem = tmpElem; 
+              }
+              else // found it!
+              {
+                break;
+              }
+              n++;
+            }
+          }
+        }
+        if (focusItem)
+        {
+          focusItem.focus();
+        }
+        else // return focus to search field
+        {
+           parent.document.getElementById("MSearchField").focus();
+        }
+      }
+      else if (this.lastKey==40) // Down
+      {
+        var newIndex = itemIndex+1;
+        var focusItem;
+        var item = document.getElementById('Item'+itemIndex);
+        var elem = this.FindChildElement(item.parentNode.parentNode.id);
+        if (elem && elem.style.display == 'block') // children visible
+        {
+          focusItem = document.getElementById('Item'+itemIndex+'_c0');
+        }
+        if (!focusItem) focusItem = this.NavNext(newIndex);
+        if (focusItem)  focusItem.focus();
+      }
+      else if (this.lastKey==39) // Right
+      {
+        var item = document.getElementById('Item'+itemIndex);
+        var elem = this.FindChildElement(item.parentNode.parentNode.id);
+        if (elem) elem.style.display = 'block';
+      }
+      else if (this.lastKey==37) // Left
+      {
+        var item = document.getElementById('Item'+itemIndex);
+        var elem = this.FindChildElement(item.parentNode.parentNode.id);
+        if (elem) elem.style.display = 'none';
+      }
+      else if (this.lastKey==27) // Escape
+      {
+        parent.searchBox.CloseResultsWindow();
+        parent.document.getElementById("MSearchField").focus();
+      }
+      else if (this.lastKey==13) // Enter
+      {
+        return true;
+      }
+      return false;
+    }
+
+    this.NavChild = function(evt,itemIndex,childIndex)
+    {
+      var e  = (evt) ? evt : window.event; // for IE
+      if (e.keyCode==13) return true;
+      if (!this.ProcessKeys(e)) return false;
+
+      if (this.lastKey==38) // Up
+      {
+        if (childIndex>0)
+        {
+          var newIndex = childIndex-1;
+          document.getElementById('Item'+itemIndex+'_c'+newIndex).focus();
+        }
+        else // already at first child, jump to parent
+        {
+          document.getElementById('Item'+itemIndex).focus();
+        }
+      }
+      else if (this.lastKey==40) // Down
+      {
+        var newIndex = childIndex+1;
+        var elem = document.getElementById('Item'+itemIndex+'_c'+newIndex);
+        if (!elem) // last child, jump to parent next parent
+        {
+          elem = this.NavNext(itemIndex+1);
+        }
+        if (elem)
+        {
+          elem.focus();
+        } 
+      }
+      else if (this.lastKey==27) // Escape
+      {
+        parent.searchBox.CloseResultsWindow();
+        parent.document.getElementById("MSearchField").focus();
+      }
+      else if (this.lastKey==13) // Enter
+      {
+        return true;
+      }
+      return false;
+    }
 }
diff --git a/src/search_css.h b/src/search_css.h
index 177dbe3..65ffed2 100644
--- a/src/search_css.h
+++ b/src/search_css.h
@@ -17,11 +17,12 @@
 "    color: #999999;\n"
 "    background-color: #FFFFFF;\n"
 "    font-style: normal;\n"
-"    cursor: pointer;\n"
+"    cursor: text;\n"
 "    padding: 0px 1px;\n"
 "    margin: 0px 6px 0px 0px;\n"
 "    border: none;\n"
 "    outline: none;\n"
+"    vertical-align: middle;\n"
 "}\n"
 "#MSearchBox.MSearchBoxInactive:hover #MSearchField {\n"
 "    background-color: #FFFFFF;\n"
@@ -41,14 +42,26 @@
 "    display : inline;\n"
 "    background : none;\n"
 "    font: 9pt Verdana, sans-serif;\n"
-"    margin-right: -6px;\n"
-"    padding: 0;\n"
 "    border: none;\n"
 "    margin: 0px 0px 0px 6px;\n"
-"    vertical-align: bottom;\n"
+"    vertical-align: middle;\n"
+"    padding: 0px 0px;\n"
+"}\n"
+"\n"
+"#MSearchClose {\n"
+"    float : none;\n"
+"    display : none;\n"
+"    background : none;\n"
+"    border: none;\n"
+"    margin: 0px 4px 0px 0px;\n"
 "    padding: 0px 0px;\n"
-"    background-color: #84B0C7;\n"
+"    outline: none;\n"
+"}\n"
+"\n"
+"#MSearchCloseImg {\n"
+"    vertical-align: middle;\n"
 "}\n"
+"\n"
 ".MSearchBoxLeft {\n"
 "    display: block;\n"
 "    text-align: left;\n"
@@ -108,7 +121,7 @@
 "    padding-left:   6px;\n"
 "    padding-right: 12px;\n"
 "}\n"
-"a.SelectItem:visited,\n"
+"a.SelectItem:focus,\n"
 "a.SelectItem:active {\n"
 "    color: #000000; \n"
 "    outline-style: none;\n"
@@ -136,26 +149,6 @@
 "    border: 1px solid #000000;\n"
 "    background-color: #EEF3F5;\n"
 "    }\n"
-"#MSearchResultsWindowClose {\n"
-"    font-weight: bold;\n"
-"    font-size: 8pt;\n"
-"    display: block;\n"
-"    padding: 0px;\n"
-"    margin: 0px;\n"
-"    text-align: right;\n"
-"    text-decoration: none;\n"
-"    outline-style: none;\n"
-"    }\n"
-"#MSearchResultsWindowClose:link,\n"
-"#MSearchResultsWindowClose:visited {\n"
-"    color: #8A8A8A;\n"
-"    background-color: #8A8A8A;\n"
-"    }\n"
-"#MSearchResultsWindowClose:active,\n"
-"#MSearchResultsWindowClose:hover {\n"
-"    color: #9E9E9E;\n"
-"    background-color: #9E9E9E;\n"
-"    }\n"
 "\n"
 "/* ----------------------------------- */\n"
 "\n"
@@ -198,6 +191,11 @@
 "    outline: none;\n"
 "}\n"
 "\n"
+"a.SRSymbol:focus, a.SRSymbol:active,\n"
+"a.SRScope:focus, a.SRScope:active {\n"
+"    text-decoration: underline;\n"
+"}\n"
+"\n"
 ".SRPage .SRStatus {\n"
 "    padding: 2px 5px;\n"
 "    font-size: 8pt;\n"
diff --git a/src/search_js.h b/src/search_js.h
index 7a401e6..d7b2a75 100644
--- a/src/search_js.h
+++ b/src/search_js.h
@@ -69,7 +69,7 @@
 "  this.lastSearchValue       = \"\";\n"
 "  this.lastResultsPage       = \"\";\n"
 "  this.hideTimeout           = 0;\n"
-"  this.searchTopic           = \"all\";\n"
+"  this.searchIndex           = 0;\n"
 "  this.searchActive          = false;\n"
 "  this.insideFrame           = inFrame;\n"
 "\n"
@@ -90,8 +90,8 @@
 "  this.DOMPopupSearchResultsWindow = function()\n"
 "  {  return document.getElementById(\"MSearchResultsWindow\");  }\n"
 "\n"
-"  this.DOMSearchResultWindowClose = function()\n"
-"  {  return document.getElementById(\"MSearchResultsWindowClose\"); }\n"
+"  this.DOMSearchClose = function()\n"
+"  {  return document.getElementById(\"MSearchClose\"); }\n"
 "\n"
 "  this.DOMSearchBox = function()\n"
 "  {  return document.getElementById(\"MSearchBox\");  }\n"
@@ -150,7 +150,7 @@
 "  }\n"
 "\n"
 "  // Called when the content of the search field is changed.\n"
-"  this.OnSearchFieldChange = function()\n"
+"  this.OnSearchFieldChange = function(evt)\n"
 "  {\n"
 "    if (this.keyTimeout) // kill running timer\n"
 "    {\n"
@@ -158,6 +158,40 @@
 "      this.keyTimeout = 0;\n"
 "    }\n"
 "\n"
+"    var e  = (evt) ? evt : window.event; // for IE\n"
+"    if (e.keyCode==40 || e.keyCode==13)\n"
+"    {\n"
+"      if (e.shiftKey==1)\n"
+"      {\n"
+"        this.OnSearchSelectShow();\n"
+"        var win=this.DOMSearchSelectWindow(); \n"
+"        for (i=0;i<win.childNodes.length;i++)\n"
+"        {\n"
+"          var child = win.childNodes[i]; // get span within a\n"
+"          if (child.className=='SelectItem')\n"
+"          {\n"
+"            child.focus();\n"
+"            return;\n"
+"          }\n"
+"        }\n"
+"        return;\n"
+"      }\n"
+"      else if (window.frames.MSearchResults.searchResults)\n"
+"      {\n"
+"        var elem = window.frames.MSearchResults.searchResults.NavNext(0);\n"
+"        if (elem) elem.focus();\n"
+"      }\n"
+"    }\n"
+"    else if (e.keyCode==27) // Escape out of the search field\n"
+"    {\n"
+"      this.DOMSearchField().blur();\n"
+"      this.DOMPopupSearchResultsWindow().style.display = 'none';\n"
+"      this.DOMSearchClose().style.display = 'none';\n"
+"      this.lastSearchValue = '';\n"
+"      this.Activate(false);\n"
+"      return;\n"
+"    }\n"
+"\n"
 "    // strip whitespaces\n"
 "    var searchValue = this.DOMSearchField().value.replace(/ +/g, \"\");\n"
 "\n"
@@ -172,14 +206,28 @@
 "      else // empty search field\n"
 "      {\n"
 "        this.DOMPopupSearchResultsWindow().style.display = 'none';\n"
+"        this.DOMSearchClose().style.display = 'none';\n"
 "        this.lastSearchValue = '';\n"
 "      }\n"
 "    }\n"
 "  }\n"
 "\n"
-"  // Called when an search filter selection is made.\n"
-"  // set item with index id as the active item\n"
-"  this.OnSelectItem = function(id,topic)\n"
+"  this.SelectItemCount = function(id)\n"
+"  {\n"
+"    var count=0;\n"
+"    var win=this.DOMSearchSelectWindow(); \n"
+"    for (i=0;i<win.childNodes.length;i++)\n"
+"    {\n"
+"      var child = win.childNodes[i]; // get span within a\n"
+"      if (child.className=='SelectItem')\n"
+"      {\n"
+"        count++;\n"
+"      }\n"
+"    }\n"
+"    return count;\n"
+"  }\n"
+"\n"
+"  this.SelectItemSet = function(id)\n"
 "  {\n"
 "    var i,j=0;\n"
 "    var win=this.DOMSearchSelectWindow(); \n"
@@ -191,7 +239,6 @@
 "        var node = child.firstChild;\n"
 "	if (j==id)\n"
 "	{\n"
-"          // add a tickmark: see http://doogalbellend.blogspot.com/2007/05/even-more-on-tick-marks-in-html.html\n"
 "          node.innerHTML='&bull;';\n"
 "        } \n"
 "        else\n"
@@ -201,31 +248,39 @@
 "        j++;\n"
 "      }\n"
 "    }\n"
-"    if (topic)\n"
-"    {\n"
-"      this.searchTopic = topic;\n"
-"      var searchValue = this.DOMSearchField().value.replace(/ +/g, \"\");\n"
-"      if (searchValue != \"\" && this.searchActive) // something was found -> do a search\n"
-"      {\n"
-"        this.Search();\n"
-"      }\n"
-"    }\n"
-"    else\n"
+"  }\n"
+"\n"
+"  // Called when an search filter selection is made.\n"
+"  // set item with index id as the active item\n"
+"  this.OnSelectItem = function(id)\n"
+"  {\n"
+"    this.searchIndex = id;\n"
+"    this.SelectItemSet(id);\n"
+"    var searchValue = this.DOMSearchField().value.replace(/ +/g, \"\");\n"
+"    if (searchValue!=\"\" && this.searchActive) // something was found -> do a search\n"
 "    {\n"
-"      this.Activate(false);\n"
+"      this.Search();\n"
 "    }\n"
 "  }\n"
 "\n"
-"  this.OnCloseHighlight = function(active)\n"
+"  this.OnSearchSelectKey = function(evt)\n"
 "  {\n"
-"    var close = this.DOMSearchResultWindowClose();\n"
-"    if (active)\n"
+"    var e = (evt) ? evt : window.event; // for IE\n"
+"    if (e.keyCode==40 && this.searchIndex<this.SelectItemCount()) // Down\n"
 "    {\n"
-"      close.firstChild.src = this.resultsPath + '/close_active.png';\n"
+"      this.searchIndex++;\n"
+"      this.OnSelectItem(this.searchIndex);\n"
 "    }\n"
-"    else\n"
+"    else if (e.keyCode==38 && this.searchIndex>0) // Up\n"
+"    {\n"
+"      this.searchIndex--;\n"
+"      this.OnSelectItem(this.searchIndex);\n"
+"    }\n"
+"    else if (e.keyCode==13 || e.keyCode==27)\n"
 "    {\n"
-"      close.firstChild.src = this.resultsPath + '/close.png';\n"
+"      this.OnSelectItem(this.searchIndex);\n"
+"      this.CloseSelectionWindow();\n"
+"      this.DOMSearchField().focus();\n"
 "    }\n"
 "    return false;\n"
 "  }\n"
@@ -235,13 +290,14 @@
 "  // Closes the results window.\n"
 "  this.CloseResultsWindow = function()\n"
 "  {\n"
-"    this.DOMPopupSearchResultsWindow().style.display = \"none\";\n"
+"    this.DOMPopupSearchResultsWindow().style.display = 'none';\n"
+"    this.DOMSearchClose().style.display = 'none';\n"
 "    this.Activate(false);\n"
 "  }\n"
 "\n"
 "  this.CloseSelectionWindow = function()\n"
 "  {\n"
-"    this.DOMSearchSelectWindow().style.display = \"none\";\n"
+"    this.DOMSearchSelectWindow().style.display = 'none';\n"
 "  }\n"
 "\n"
 "  // Performs a search.\n"
@@ -267,10 +323,9 @@
 "    var resultsPageWithSearch;\n"
 "    var hasResultsPage;\n"
 "\n"
-"    // indexSectionsWithContent is defined in searchdata.js\n"
-"    if (indexSectionsWithContent[this.searchTopic].charAt(code-32) == '1')\n"
+"    if (indexSectionsWithContent[this.searchIndex].charAt(code-32) == '1')\n"
 "    {\n"
-"       resultsPage = this.resultsPath + '/' + this.searchTopic + '_' + hexCode + '.html';\n"
+"       resultsPage = this.resultsPath + '/' + indexSectionNames[this.searchIndex] + '_' + hexCode + '.html';\n"
 "       resultsPageWithSearch = resultsPage+'?'+escape(searchValue);\n"
 "       hasResultsPage = true;\n"
 "    }\n"
@@ -284,13 +339,13 @@
 "    window.frames.MSearchResults.location.href = resultsPageWithSearch;  \n"
 "    var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow();\n"
 "\n"
-"    if (domPopupSearchResultsWindow.style.display!=\"block\")\n"
+"    if (domPopupSearchResultsWindow.style.display!='block')\n"
 "    {\n"
+"       var domSearchBox = this.DOMSearchBox();\n"
+"       this.DOMSearchClose().style.display = 'inline';\n"
 "       if (this.insideFrame)\n"
 "       {\n"
-"         var domSearchBox = this.DOMSearchBox();\n"
 "         var domPopupSearchResults = this.DOMPopupSearchResults();\n"
-"         this.DOMSearchResultWindowClose().style.textAlign = 'left';\n"
 "         domPopupSearchResultsWindow.style.position = 'relative';\n"
 "         domPopupSearchResultsWindow.style.display  = 'block';\n"
 "         var width = document.body.clientWidth - 8; // the -8 is for IE :-(\n"
@@ -299,10 +354,9 @@
 "       }\n"
 "       else\n"
 "       {\n"
-"         var domSearchField = this.DOMSearchField();\n"
 "         var domPopupSearchResults = this.DOMPopupSearchResults();\n"
-"         var left = getXPos(domSearchField) + domSearchField.offsetWidth;\n"
-"         var top  = getYPos(domSearchField) + domSearchField.offsetHeight + 1;\n"
+"         var left = getXPos(domSearchBox) + domSearchBox.offsetWidth;\n"
+"         var top  = getYPos(domSearchBox) + domSearchBox.offsetHeight + 1;\n"
 "         domPopupSearchResultsWindow.style.display = 'block';\n"
 "         left -= domPopupSearchResults.offsetWidth;\n"
 "         domPopupSearchResultsWindow.style.top     = top  + 'px';\n"
@@ -352,9 +406,11 @@
 "{\n"
 "    // The number of matches from the last run of <Search()>.\n"
 "    this.lastMatchCount = 0;\n"
+"    this.lastKey = 0;\n"
+"    this.repeatOn = false;\n"
 "\n"
 "    // Toggles the visibility of the passed element ID.\n"
-"    this.Toggle = function(id)\n"
+"    this.FindChildElement = function(id)\n"
 "    {\n"
 "      var parentElement = document.getElementById(id);\n"
 "      var element = parentElement.firstChild;\n"
@@ -363,14 +419,7 @@
 "      {\n"
 "        if (element.nodeName == 'DIV' && element.className == 'SRChildren')\n"
 "        {\n"
-"          if (element.style.display == 'block')\n"
-"          {  \n"
-"            element.style.display = 'none';  \n"
-"          }\n"
-"          else\n"
-"          {  \n"
-"            element.style.display = 'block';  \n"
-"          }\n"
+"          return element;\n"
 "        }\n"
 "\n"
 "        if (element.nodeName == 'DIV' && element.hasChildNodes())\n"
@@ -397,6 +446,22 @@
 "      }\n"
 "    }\n"
 "\n"
+"    this.Toggle = function(id)\n"
+"    {\n"
+"      var element = this.FindChildElement(id);\n"
+"      if (element)\n"
+"      {\n"
+"        if (element.style.display == 'block')\n"
+"        {  \n"
+"          element.style.display = 'none';  \n"
+"        }\n"
+"        else\n"
+"        {  \n"
+"          element.style.display = 'block';  \n"
+"        }\n"
+"      }\n"
+"    }\n"
+"\n"
 "    // Searches for the passed string.  If there is no parameter, \n"
 "    // it takes it from the URL query.\n"
 "    //\n"
@@ -431,26 +496,213 @@
 "          if (search.length<=rowMatchName.length && \n"
 "             rowMatchName.substr(0, search.length)==search)\n"
 "          {\n"
-"            row.style.display = \"block\";\n"
+"            row.style.display = 'block';\n"
 "            matches++;\n"
 "          }\n"
 "          else\n"
 "          {  \n"
-"            row.style.display = \"none\";  \n"
+"            row.style.display = 'none';  \n"
 "          }\n"
 "        }\n"
 "        i++;\n"
 "      }\n"
-"      document.getElementById(\"Searching\").style.display=\"none\";\n"
+"      document.getElementById(\"Searching\").style.display='none';\n"
 "      if (matches == 0) // no results\n"
 "      {  \n"
-"        document.getElementById(\"NoMatches\").style.display=\"block\";  \n"
+"        document.getElementById(\"NoMatches\").style.display='block';  \n"
 "      }\n"
 "      else // at least one result\n"
 "      {  \n"
-"        document.getElementById(\"NoMatches\").style.display=\"none\";  \n"
+"        document.getElementById(\"NoMatches\").style.display='none';  \n"
 "      }\n"
 "      this.lastMatchCount = matches;\n"
 "      return true;\n"
 "    }\n"
+"\n"
+"    // return the first item with index index or higher that is visible\n"
+"    this.NavNext = function(index)\n"
+"    {\n"
+"      var focusItem;\n"
+"      while (1)\n"
+"      {\n"
+"        var focusName = 'Item'+index;\n"
+"        focusItem = document.getElementById(focusName);\n"
+"        if (focusItem && focusItem.parentNode.parentNode.style.display=='block')\n"
+"        {\n"
+"          break;\n"
+"        }\n"
+"        else if (!focusItem) // last element\n"
+"        {\n"
+"          break;\n"
+"        }\n"
+"        focusItem=null;\n"
+"        index++;\n"
+"      }\n"
+"      return focusItem;\n"
+"    }\n"
+"\n"
+"    this.NavPrev = function(index)\n"
+"    {\n"
+"      var focusItem;\n"
+"      while (1)\n"
+"      {\n"
+"        var focusName = 'Item'+index;\n"
+"        focusItem = document.getElementById(focusName);\n"
+"        if (focusItem && focusItem.parentNode.parentNode.style.display=='block')\n"
+"        {\n"
+"          break;\n"
+"        }\n"
+"        else if (!focusItem) // last element\n"
+"        {\n"
+"          break;\n"
+"        }\n"
+"        focusItem=null;\n"
+"        index--;\n"
+"      }\n"
+"      return focusItem;\n"
+"    }\n"
+"\n"
+"    this.ProcessKeys = function(e)\n"
+"    {\n"
+"      if (e.type == \"keydown\") \n"
+"      {\n"
+"        this.repeatOn = false;\n"
+"        this.lastKey = e.keyCode;\n"
+"      }\n"
+"      else if (e.type == \"keypress\")\n"
+"      {\n"
+"        if (!this.repeatOn)\n"
+"        {\n"
+"          if (this.lastKey) this.repeatOn = true;\n"
+"          return false; // ignore first keypress after keydown\n"
+"        }\n"
+"      }\n"
+"      else if (e.type == \"keyup\")\n"
+"      {\n"
+"        this.lastKey = 0;\n"
+"        this.repeatOn = false;\n"
+"      }\n"
+"      return this.lastKey!=0;\n"
+"    }\n"
+"\n"
+"    this.Nav = function(evt,itemIndex) \n"
+"    {\n"
+"      var e  = (evt) ? evt : window.event; // for IE\n"
+"      if (e.keyCode==13) return true;\n"
+"      if (!this.ProcessKeys(e)) return false;\n"
+"\n"
+"      if (this.lastKey==38) // Up\n"
+"      {\n"
+"        var newIndex = itemIndex-1;\n"
+"        var focusItem = this.NavPrev(newIndex);\n"
+"        if (focusItem)\n"
+"        {\n"
+"          var child = this.FindChildElement(focusItem.parentNode.parentNode.id);\n"
+"          if (child && child.style.display == 'block') // children visible\n"
+"          { \n"
+"            var n=0;\n"
+"            var tmpElem;\n"
+"            while (1) // search for last child\n"
+"            {\n"
+"              tmpElem = document.getElementById('Item'+newIndex+'_c'+n);\n"
+"              if (tmpElem) \n"
+"              {\n"
+"                focusItem = tmpElem; \n"
+"              }\n"
+"              else // found it!\n"
+"              {\n"
+"                break;\n"
+"              }\n"
+"              n++;\n"
+"            }\n"
+"          }\n"
+"        }\n"
+"        if (focusItem)\n"
+"        {\n"
+"          focusItem.focus();\n"
+"        }\n"
+"        else // return focus to search field\n"
+"        {\n"
+"           parent.document.getElementById(\"MSearchField\").focus();\n"
+"        }\n"
+"      }\n"
+"      else if (this.lastKey==40) // Down\n"
+"      {\n"
+"        var newIndex = itemIndex+1;\n"
+"        var focusItem;\n"
+"        var item = document.getElementById('Item'+itemIndex);\n"
+"        var elem = this.FindChildElement(item.parentNode.parentNode.id);\n"
+"        if (elem && elem.style.display == 'block') // children visible\n"
+"        {\n"
+"          focusItem = document.getElementById('Item'+itemIndex+'_c0');\n"
+"        }\n"
+"        if (!focusItem) focusItem = this.NavNext(newIndex);\n"
+"        if (focusItem)  focusItem.focus();\n"
+"      }\n"
+"      else if (this.lastKey==39) // Right\n"
+"      {\n"
+"        var item = document.getElementById('Item'+itemIndex);\n"
+"        var elem = this.FindChildElement(item.parentNode.parentNode.id);\n"
+"        if (elem) elem.style.display = 'block';\n"
+"      }\n"
+"      else if (this.lastKey==37) // Left\n"
+"      {\n"
+"        var item = document.getElementById('Item'+itemIndex);\n"
+"        var elem = this.FindChildElement(item.parentNode.parentNode.id);\n"
+"        if (elem) elem.style.display = 'none';\n"
+"      }\n"
+"      else if (this.lastKey==27) // Escape\n"
+"      {\n"
+"        parent.searchBox.CloseResultsWindow();\n"
+"        parent.document.getElementById(\"MSearchField\").focus();\n"
+"      }\n"
+"      else if (this.lastKey==13) // Enter\n"
+"      {\n"
+"        return true;\n"
+"      }\n"
+"      return false;\n"
+"    }\n"
+"\n"
+"    this.NavChild = function(evt,itemIndex,childIndex)\n"
+"    {\n"
+"      var e  = (evt) ? evt : window.event; // for IE\n"
+"      if (e.keyCode==13) return true;\n"
+"      if (!this.ProcessKeys(e)) return false;\n"
+"\n"
+"      if (this.lastKey==38) // Up\n"
+"      {\n"
+"        if (childIndex>0)\n"
+"        {\n"
+"          var newIndex = childIndex-1;\n"
+"          document.getElementById('Item'+itemIndex+'_c'+newIndex).focus();\n"
+"        }\n"
+"        else // already at first child, jump to parent\n"
+"        {\n"
+"          document.getElementById('Item'+itemIndex).focus();\n"
+"        }\n"
+"      }\n"
+"      else if (this.lastKey==40) // Down\n"
+"      {\n"
+"        var newIndex = childIndex+1;\n"
+"        var elem = document.getElementById('Item'+itemIndex+'_c'+newIndex);\n"
+"        if (!elem) // last child, jump to parent next parent\n"
+"        {\n"
+"          elem = this.NavNext(itemIndex+1);\n"
+"        }\n"
+"        if (elem)\n"
+"        {\n"
+"          elem.focus();\n"
+"        } \n"
+"      }\n"
+"      else if (this.lastKey==27) // Escape\n"
+"      {\n"
+"        parent.searchBox.CloseResultsWindow();\n"
+"        parent.document.getElementById(\"MSearchField\").focus();\n"
+"      }\n"
+"      else if (this.lastKey==13) // Enter\n"
+"      {\n"
+"        return true;\n"
+"      }\n"
+"      return false;\n"
+"    }\n"
 "}\n"
diff --git a/src/util.cpp b/src/util.cpp
index ec8f8db..d6519c4 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -305,7 +305,8 @@ int guessSection(const char *name)
       n.right(4)==".ixx"  ||
       n.right(4)==".ipp"  ||
       n.right(4)==".i++"  ||
-      n.right(4)==".inl"
+      n.right(4)==".inl"  ||
+      n.right(4)==".xml"
      ) return Entry::SOURCE_SEC;
   if (n.right(2)==".h"   || // header
       n.right(3)==".hh"  ||
@@ -6069,22 +6070,6 @@ static void latin2ToLatex(QTextStream &t,unsigned char c)
 void filterLatexString(QTextStream &t,const char *str,
     bool insideTabbing,bool insidePre,bool insideItem)
 {
-#if 0
-  static bool isCzech         = theTranslator->idLanguage()=="czech";
-  static bool isSerbian       = theTranslator->idLanguage()=="serbian";
-  static bool isJapanese      = theTranslator->idLanguage()=="japanese" ||
-    theTranslator->idLanguage()=="japanese-en";
-  static bool isKorean        = theTranslator->idLanguage()=="korean" ||
-    theTranslator->idLanguage()=="korean-en";
-  static bool isRussian       = theTranslator->idLanguage()=="russian";
-  static bool isUkrainian     = theTranslator->idLanguage()=="ukrainian";
-  static bool isSlovene       = theTranslator->idLanguage()=="solvene";
-  static bool isChinese       = theTranslator->idLanguage()=="chinese" || 
-    theTranslator->idLanguage()=="chinese-traditional";
-  static bool isLatin2        = theTranslator->idLanguageCharset()=="iso-8859-2";
-  static bool isGreek         = theTranslator->idLanguage()=="greek";
-  //printf("filterLatexString(%s)\n",str);
-#endif
   if (str)
   {
     const unsigned char *p=(const unsigned char *)str;
@@ -6104,25 +6089,6 @@ void filterLatexString(QTextStream &t,const char *str,
           case '_':  t << "\\_"; break;
           default: 
                      t << (char)c;
-#if 0
-                     {
-                       // Some languages use wide characters
-                       if (c>=128 && (isJapanese || isKorean || isChinese || isSerbian))
-                       { 
-                         t << (char)c;
-                         if (*p)  
-                         {
-                           c = *p++;
-                           t << (char)c;
-                         }
-                       }
-                       else
-                       {
-                         t << (char)c; 
-                       }
-                       break;
-                     }
-#endif
         }
       }
       else
@@ -6155,10 +6121,7 @@ void filterLatexString(QTextStream &t,const char *str,
                        else
                          t << "]";             
                      break;
-          case '-':  if (*p=='>') 
-                     { t << " $\\rightarrow$ "; p++; }
-                     else
-                     { t << (char)c; }
+          case '-':  t << "-\\/";
                      break;
           case '\\': if (*p=='<') 
                      { t << "$<$"; p++; }
@@ -6445,6 +6408,7 @@ g_lang2extMap[] =
   { "python",      "python",  SrcLangExt_Python },
   { "fortran",     "fortran", SrcLangExt_F90    },
   { "vhdl",        "vhdl",    SrcLangExt_VHDL   },
+  { "dbusxml",     "dbusxml", SrcLangExt_XML    },
   { 0,             0,        (SrcLangExt)0      }
 };
 
@@ -6507,6 +6471,7 @@ void initDefaultExtensionMapping()
   updateLanguageMapping(".f90",   "fortran");
   updateLanguageMapping(".vhd",   "vhdl");
   updateLanguageMapping(".vhdl",  "vhdl");
+  updateLanguageMapping(".xml",   "dbusxml");
 }
 
 SrcLangExt getLanguageFromFileName(const QCString fileName)
diff --git a/src/util.h b/src/util.h
index d3d10fd..10f125f 100644
--- a/src/util.h
+++ b/src/util.h
@@ -95,7 +95,8 @@ enum SrcLangExt
   SrcLangExt_JS     = 0x0400,
   SrcLangExt_Python = 0x0800,
   SrcLangExt_F90    = 0x1000,
-  SrcLangExt_VHDL   = 0x2000
+  SrcLangExt_VHDL   = 0x2000,
+  SrcLangExt_XML    = 0x4000
 };
 
 //--------------------------------------------------------------------
-- 
cgit v0.12

