Index: /quintagroup.dropdownmenu/tags/1.2.9/MANIFEST.in
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/MANIFEST.in	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/MANIFEST.in	(revision 3460)
@@ -0,0 +1,4 @@
+recursive-include docs *
+recursive-include quintagroup *
+global-exclude *.pyc
+global-exclude *.mo
Index: /quintagroup.dropdownmenu/tags/1.2.9/README.txt
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/README.txt	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/README.txt	(revision 3460)
@@ -0,0 +1,67 @@
+Introduction
+------------
+
+This package allows to build dropdown menu through the web with portal_actions.
+Submenus are built from a tree of nested Category Actions and Actions.
+
+The other strategy used to populate submenus is Plone default NavigationStrategy, 
+the one used in navigation portlet.  
+
+This project is successor of qPloneDropDownMenu. 
+
+Building you dropdown menu with portal_actions
+==============================================
+
+Starting from Plone 3 portal actions introduced CMF Action Category 
+containers, it opened opportunity to build nested actions trees. Though CMF Action 
+Category does not behave as a regular action, it has different set of properties. 
+We introduced convention in quintagroup.dropdownmenu that requires to have 
+a specially named Action for each Actions Category. The id of each such action 
+must be build using the rule::
+  
+  action_id = prefix + category_id + suffix
+   
+where:
+  
+:category_id: is id of correspondent CMF Action Category    
+:prefix: defined in DropDownMenu configlet, default value ''
+:suffix: defined in DropDownMenu configlet, default value '_sub'
+
+So, the actions structure can look like::
+
+  + portal_tabs
+  |- home
+  |- blog_sub
+  |-+ blog
+  | |-- 2009
+  | |-- 2010
+     
+By default the root of dropdown menu is 'portal_tabs' category.
+
+Menu caching
+============
+
+If the menu built with Navigation strategy is entirely public it can be cached for
+all users. If Authenticaded users should see some non public items the menu can be
+cached for anonymous only.
+
+Caching in case of involving the portal_actions strategy is effective only in case
+if all the action are public and have no extra conditions. In case some conditions
+are applied per action switch off caching.
+
+ 
+Compatibility
+=============
+
+* **Plone 4** sample CSS file based on Sunburst theme provided
+* **Plone 3.0-3.3** the default CSS file has to be overridden
+
+Installation
+============
+
+* add http://good-py.appspot.com/release/plone.app.registry/1.0b2 to versions in your buildout
+* add quintagroup.dropdownmenu to eggs in your buildout
+* install Plone DropDown Menu in Plone via Site Setup -> Add-ons
+
+Find more details on the topic inside docs/INSTALL.txt 
+
Index: /quintagroup.dropdownmenu/tags/1.2.9/docs/CONTRIBUTORS.txt
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/docs/CONTRIBUTORS.txt	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/docs/CONTRIBUTORS.txt	(revision 3460)
@@ -0,0 +1,9 @@
+Contributors
+============
+
+Volodymyr Cherepanyak   [chevol]
+Vitaliy Podoba  [piv]
+Yuriy Gvozdovych    [gvizdyk]
+Olha Pelishok   [olha]
+Taras Melnychuk [fenix]
+Malthe Borch
Index: /quintagroup.dropdownmenu/tags/1.2.9/docs/HISTORY.txt
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/docs/HISTORY.txt	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/docs/HISTORY.txt	(revision 3460)
@@ -0,0 +1,65 @@
+Changelog
+=========
+
+1.2.9 - May 2, 2012
+
+* fixed issue that significantly reduced menu caching performance
+  [malthe]
+
+1.2.8 - Apr 23, 2012
+
+* fixed styles for a drop-down menu list in IE7 [gvizdyk]
+
+1.2.7 - Jan 31, 2012
+
+* added cache switch for tabs
+
+1.2.6 - Jan 26, 2012
+
+* revisited caching key strategies, added language and anonymous switch 
+* added caching switch to control panel
+
+1.2.5 - Oct 21, 2011
+
+* added cache header for csshover.htc view
+  to allow proxy and browser to cache it. 
+
+1.2.4 - Sep 07, 2011
+
+* documentation formatting fixed
+
+1.2.3 - Sep 05, 2011
+
+* Live search with dropdown menu overlaps fixed
+
+1.2.2 - June 21, 2011
+
+* Fixed caching content tabs and action tabs
+* portal_action generated menu caching is conditional and switched off for now
+
+1.2.1 - June 15, 2011
+
+* Caching fixed
+
+1.2 - Apr 6, 2011
+
+* Changed z3c.autoinclude includeDependencies to simple include to work in plone 3.2 [kroman0]
+* drop-down overlay bug fixed [wald]
+* cleared unnecessary classes, changed styles to current and hover element [gvizdyk]
+* Fixed uninstallation. Added unisntallation with QI [mylan]
+* Tests refactoring [mylan]
+
+1.1.1 - Sep 23, 2010
+
+* fixed the docs markup [chervol]
+
+1.1 - Sep 22, 2010
+
+* removed debug code [chervol]
+* fixed the dropdown CSS
+* fixed the Home tab highlight
+
+1.0 - Sep 08, 2010
+
+* Initial release
+
Index: /quintagroup.dropdownmenu/tags/1.2.9/docs/INSTALL.txt
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/docs/INSTALL.txt	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/docs/INSTALL.txt	(revision 3460)
@@ -0,0 +1,29 @@
+Installation
+------------
+
+* Fix version of ``plone.app.registry``::
+
+    [buildout]
+    ...
+    extends =
+        http://good-py.appspot.com/release/plone.app.registry/1.0b2
+
+* Add ``quintagroup.dropdownmenu`` to the list of eggs to install::
+
+    [buildout]
+    ...
+    eggs =
+        ...
+        quintagroup.dropdownmenu
+
+After that:     
+
+* Re-run buildout with::
+
+    $ ./bin/buildout
+        
+* Restart Zope server process::
+
+   $ ./bin/instance restart
+   
+Then install ``Plone DropDown Menu`` in Plone via Site Setup -> Add-ons.  
Index: /quintagroup.dropdownmenu/tags/1.2.9/docs/LICENSE.GPL
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/docs/LICENSE.GPL	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/docs/LICENSE.GPL	(revision 3460)
@@ -0,0 +1,225 @@
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
Index: /quintagroup.dropdownmenu/tags/1.2.9/docs/LICENSE.txt
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/docs/LICENSE.txt	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/docs/LICENSE.txt	(revision 3460)
@@ -0,0 +1,16 @@
+  quintagroup.dropdownmenu is copyright Vitaliy Podoba
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+  MA 02111-1307 USA.
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup.dropdownmenu-configure.zcml
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup.dropdownmenu-configure.zcml	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup.dropdownmenu-configure.zcml	(revision 3460)
@@ -0,0 +1,1 @@
+<include package="quintagroup.dropdownmenu" />
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/__init__.py
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/__init__.py	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/__init__.py	(revision 3460)
@@ -0,0 +1,6 @@
+# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/Extensions/Install.py
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/Extensions/Install.py	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/Extensions/Install.py	(revision 3460)
@@ -0,0 +1,22 @@
+import logging
+from Products.CMFCore.utils import getToolByName
+
+from quintagroup.dropdownmenu import PROJECT_NAME
+
+logger = logging.getLogger('quintagroup.dropdownmenu')
+
+UNINSTALL = "profile-%s:uninstall" % PROJECT_NAME
+
+
+def uninstall(portal, reinstall=False):
+    """ Uninstall this product.
+
+        This external method is need, because portal_quickinstaller doens't
+        know what GenericProfile profile to apply when uninstalling a product.
+    """
+    setup_tool = getToolByName(portal, 'portal_setup')
+    if reinstall:
+        return "Ran all reinstall steps."
+    else:
+        setup_tool.runAllImportStepsFromProfile(UNINSTALL)
+        return "Ran all uninstall steps."
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/TODO.txt
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/TODO.txt	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/TODO.txt	(revision 3460)
@@ -0,0 +1,16 @@
+Todo List
+
+ [ ] current element for actions based tabs
+ [ ] IE<7 functionality
+ [ ] csshover configlet
+ [ ] clean uninstall procedure
+ [ ] migration from qPloneDropDownMenu
+ [ ] documentation
+ [ ] tests tests tests
+
+
+Completed List
+
+ [x] global sections viewlet
+ [x] proxy for show_content_tabs and show_nonfolderish_tabs settings
+ [x] settings configlet
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/__init__.py
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/__init__.py	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/__init__.py	(revision 3460)
@@ -0,0 +1,7 @@
+import logging
+from zope.i18nmessageid import MessageFactory
+
+_ = MessageFactory("quintagroup.dropdownmenu")
+
+PROJECT_NAME = "quintagroup.dropdownmenu"
+logger = logging.getLogger(PROJECT_NAME)
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/__init__.py
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/__init__.py	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/__init__.py	(revision 3460)
@@ -0,0 +1,1 @@
+#
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/configure.zcml
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/configure.zcml	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/configure.zcml	(revision 3460)
@@ -0,0 +1,58 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:browser="http://namespaces.zope.org/browser"
+    i18n_domain="quintagroup.dropdownmenu">
+
+
+  <include package="plone.browserlayer" />
+
+  <browser:viewlet
+      name="plone.global_sections"
+      manager="plone.app.layout.viewlets.interfaces.IPortalHeader"
+      class=".viewlets.GlobalSectionsViewlet"
+      layer="..interfaces.IDropDownMenuLayer"
+      permission="zope2.View"
+      />
+
+  <browser:page
+      name="dropdownmenu-settings"
+      for="Products.CMFPlone.interfaces.IPloneSiteRoot"
+      class=".controlpanel.DropDownMenuSettingsControlPanel"
+      permission="cmf.ManagePortal"
+      />
+
+  <class class=".menu.DropDownMenuQueryBuilder">
+    <allow interface="plone.app.layout.navigation.interfaces.INavigationQueryBuilder" />
+  </class>
+
+  <class class=".menu.DropDownMenuStrategy">
+        <allow interface="plone.app.layout.navigation.interfaces.INavtreeStrategy" />
+  </class>
+
+  <adapter
+      for="* *"
+      factory=".menu.DropDownMenuStrategy"
+      provides="plone.app.layout.navigation.interfaces.INavtreeStrategy" />
+
+  <!-- Returns javascript which makes IE<7 understand hover for all html elements -->
+  <browser:view
+      name="csshover.htc"
+      for="*"
+      class=".css.CSSHoverView"
+      permission="zope2.View"
+      />
+
+  <!-- Register resources -->
+  <browser:resource
+      name="drop_down.css"
+      file="resources/drop_down.css"
+      />
+
+<!-- Resource directory for images -->
+  <browser:resourceDirectory
+      name="quintagroup.dropdownmenu.images"
+      directory="images"
+      layer="..interfaces.IDropDownMenuLayer"
+      />
+
+</configure>
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/controlpanel.py
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/controlpanel.py	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/controlpanel.py	(revision 3460)
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+from zope.i18n import translate
+from zope.schema.interfaces import ITitledTokenizedTerm
+
+from Products.CMFCore.utils import getToolByName
+
+from plone.app.registry.browser import controlpanel
+
+from quintagroup.dropdownmenu.interfaces import IDropDownMenuSettings, _
+
+
+class DropDownMenuSettingsEditForm(controlpanel.RegistryEditForm):
+
+    schema = IDropDownMenuSettings
+    label = _(u"DropDown Menu settings")
+    description = _(u"Please enter the options specified")
+
+    def applyChanges(self, data):
+        """To save a few fields into portal_properties tool"""
+        result = super(DropDownMenuSettingsEditForm, self).applyChanges(data)
+        self._settings(data['show_content_tabs'],
+                       data['show_nonfolderish_tabs'])
+        return result
+
+    def update(self):
+        """Also get values for a few fields from portal_properties tool"""
+        super(DropDownMenuSettingsEditForm, self).update()
+        conf = self._settings()
+        self._overrideValue(self.widgets['show_content_tabs'], not conf[0])
+        self._overrideValue(self.widgets['show_nonfolderish_tabs'],
+                            not conf[1])
+
+    def _overrideValue(self, widget, value):
+        if value:
+            widget.value = ['selected']
+
+        widget.items = []
+        for count, term in enumerate(widget.terms):
+            checked = widget.isChecked(term)
+            id = '%s-%i' % (widget.id, count)
+            label = term.token
+            if ITitledTokenizedTerm.providedBy(term):
+                label = translate(term.title, context=widget.request,
+                                  default=term.title)
+            widget.items.append({'id': id, 'name': widget.name + ':list',
+                'value': term.token, 'label': label, 'checked': checked})
+
+    def _settings(self, folder=None, nonfolderish=None):
+        """Return portal_properties settings"""
+        props = [True, True]
+        prop_tool = getToolByName(self.context, 'portal_properties')
+        if 'site_properties' in prop_tool.objectIds():
+            sheet = prop_tool._getOb('site_properties')
+            if sheet.hasProperty('disable_folder_sections'):
+                if folder is not None:
+                    sheet.manage_changeProperties(
+                        disable_folder_sections=not folder)
+                props[0] = sheet.getProperty('disable_folder_sections')
+            if sheet.hasProperty('disable_nonfolderish_sections'):
+                if nonfolderish is not None:
+                    sheet.manage_changeProperties(
+                        disable_nonfolderish_sections=not nonfolderish)
+                props[1] = sheet.getProperty('disable_nonfolderish_sections')
+        return props
+
+
+class DropDownMenuSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
+    form = DropDownMenuSettingsEditForm
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/css.py
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/css.py	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/css.py	(revision 3460)
@@ -0,0 +1,24 @@
+import os
+
+from Products.Five.browser import BrowserView
+
+
+class CSSHoverView(BrowserView):
+    """Return csshover.htc js for IE < 7, this requires python class only
+    because of need to set custom content type for that resource.
+    """
+
+    def __call__(self):
+        """Main method"""
+        resource = file(os.path.join(os.path.dirname(__file__),
+                                     'resources', 'csshover.htc'), 'r').read()
+        response = self.request.response
+        response.setHeader('Content-Type', 'text/x-component')
+
+        # cache in browser for 1 year and in proxy for 2 month
+        response.setHeader('Cache-Control',
+                           'max-age=31536000, s-maxage=5184000, public')
+
+        # enabling gzip compression
+        response.enableHTTPCompression(REQUEST=self.request)
+        return resource
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/menu.py
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/menu.py	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/menu.py	(revision 3460)
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+from zope.interface import implements
+
+from Products.CMFPlone.browser.navtree import SitemapQueryBuilder
+from Products.CMFPlone.browser.navtree import DefaultNavtreeStrategy
+
+from plone.app.layout.navigation.interfaces import INavtreeStrategy
+from plone.app.layout.navigation.interfaces import INavigationQueryBuilder
+
+from quintagroup.dropdownmenu.util import getDropDownMenuSettings
+
+
+class DropDownMenuQueryBuilder(SitemapQueryBuilder):
+
+    implements(INavigationQueryBuilder)
+
+    def __init__(self, context):
+        super(DropDownMenuQueryBuilder, self).__init__(context)
+        self.context = context
+
+        # customize depth according to dropdown menu settings
+        if self._settings.content_tabs_level > 0:
+            self.query['path']['depth'] = self._settings.content_tabs_level
+        elif 'depth' in self.query['path']:
+            del self.query['path']['depth']
+
+        # constrain non-folderish objects if required
+        if not self._settings.show_nonfolderish_tabs:
+            self.query['is_folderish'] = True
+
+    @property
+    def _settings(self):
+        """Fetch dropdown menu settings registry"""
+        return getDropDownMenuSettings(self.context)
+
+
+class DropDownMenuStrategy(DefaultNavtreeStrategy):
+
+    implements(INavtreeStrategy)
+
+    def __init__(self, context, view=None):
+        super(DropDownMenuStrategy, self).__init__(context, view)
+        self.bottomLevel = self._settings.content_tabs_level
+
+    @property
+    def _settings(self):
+        """Fetch dropdown menu settings registry"""
+        return getDropDownMenuSettings(self.context)
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/resources/csshover.htc
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/resources/csshover.htc	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/resources/csshover.htc	(revision 3460)
@@ -0,0 +1,120 @@
+<attach event="ondocumentready" handler="parseStylesheets" />
+<script>
+/**
+ *	Whatever:hover - V1.42.060206 - hover & active
+ *	------------------------------------------------------------
+ *	(c) 2005 - Peter Nederlof
+ *	Peterned - http://www.xs4all.nl/~peterned/
+ *	License  - http://creativecommons.org/licenses/LGPL/2.1/
+ *
+ *	Whatever:hover is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation; either
+ *	version 2.1 of the License, or (at your option) any later version.
+ *
+ *	Whatever:hover is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ *	Lesser General Public License for more details.
+ *
+ *	Credits and thanks to:
+ *	Arnoud Berendsen, Martin Reurings, Robert Hanson
+ *
+ *	howto: body { behavior:url("csshover.htc"); }
+ *	------------------------------------------------------------
+ */
+
+var csshoverReg = /(^|\s)(([^a]([^ ]+)?)|(a([^#.][^ ]+)+)):(hover|active)/i,
+currentSheet, doc = window.document, hoverEvents = [], activators = {
+	onhover:{on:'onmouseover', off:'onmouseout'},
+	onactive:{on:'onmousedown', off:'onmouseup'}
+}
+
+function parseStylesheets() {
+	if(!/MSIE (5|6)/.test(navigator.userAgent)) return;
+	window.attachEvent('onunload', unhookHoverEvents);
+	var sheets = doc.styleSheets, l = sheets.length;
+	for(var i=0; i<l; i++) 
+		parseStylesheet(sheets[i]);
+}
+	function parseStylesheet(sheet) {
+		if(sheet.imports) {
+			try {
+				var imports = sheet.imports, l = imports.length;
+				for(var i=0; i<l; i++) parseStylesheet(sheet.imports[i]);
+			} catch(securityException){}
+		}
+
+		try {
+			var rules = (currentSheet = sheet).rules, l = rules.length;
+			for(var j=0; j<l; j++) parseCSSRule(rules[j]);
+		} catch(securityException){}
+	}
+
+	function parseCSSRule(rule) {
+		var select = rule.selectorText, style = rule.style.cssText;
+		if(!csshoverReg.test(select) || !style) return;
+
+		var pseudo = select.replace(/[^:]+:([a-z-]+).*/i, 'on$1');
+		var newSelect = select.replace(/(\.([a-z0-9_-]+):[a-z]+)|(:[a-z]+)/gi, '.$2' + pseudo);
+		var className = (/\.([a-z0-9_-]*on(hover|active))/i).exec(newSelect)[1];
+		var affected = select.replace(/:(hover|active).*$/, '');
+		var elements = getElementsBySelect(affected);
+		if(elements.length == 0) return;
+
+		currentSheet.addRule(newSelect, style);
+		for(var i=0; i<elements.length; i++)
+			new HoverElement(elements[i], className, activators[pseudo]);
+	}
+
+function HoverElement(node, className, events) {
+	if(!node.hovers) node.hovers = {};
+	if(node.hovers[className]) return;
+	node.hovers[className] = true;
+	hookHoverEvent(node, events.on, function() { node.className += ' ' + className; });
+	hookHoverEvent(node, events.off, function() { node.className = node.className.replace(new RegExp('\\s+'+className, 'g'),''); });
+}
+	function hookHoverEvent(node, type, handler) {
+		node.attachEvent(type, handler);
+		hoverEvents[hoverEvents.length] = { 
+			node:node, type:type, handler:handler 
+		};
+	}
+
+	function unhookHoverEvents() {
+		for(var e,i=0; i<hoverEvents.length; i++) {
+			e = hoverEvents[i]; 
+			e.node.detachEvent(e.type, e.handler);
+		}
+	}
+
+function getElementsBySelect(rule) {
+	var parts, nodes = [doc];
+	parts = rule.split(' ');
+	for(var i=0; i<parts.length; i++) {
+		nodes = getSelectedNodes(parts[i], nodes);
+	}	return nodes;
+}
+	function getSelectedNodes(select, elements) {
+		var result, node, nodes = [];
+		var identify = (/\#([a-z0-9_-]+)/i).exec(select);
+		if(identify) {
+			var element = doc.getElementById(identify[1]);
+			return element? [element]:nodes;
+		}
+		
+		var classname = (/\.([a-z0-9_-]+)/i).exec(select);
+		var tagName = select.replace(/(\.|\#|\:)[a-z0-9_-]+/i, '');
+		var classReg = classname? new RegExp('\\b' + classname[1] + '\\b'):false;
+		for(var i=0; i<elements.length; i++) {
+			result = tagName? elements[i].all.tags(tagName):elements[i].all; 
+			for(var j=0; j<result.length; j++) {
+				node = result[j];
+				if(classReg && !classReg.test(node.className)) continue;
+				nodes[nodes.length] = node;
+			}
+		}	
+		
+		return nodes;
+	}
+</script>
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/resources/drop_down.css
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/resources/drop_down.css	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/resources/drop_down.css	(revision 3460)
@@ -0,0 +1,97 @@
+/* DropDown Menu Styles */
+
+body {
+  behavior:url("/@@csshover.htc");
+  }
+#portal-top {
+  z-index:1;
+  }
+#portal-searchbox {
+  position:relative;
+  z-index:2;
+  }  
+
+/*---------- BASIC STYLE one level ----------*/
+#portal-globalnav {
+  list-style-image:none;
+  position:relative; /* fix ie */
+  zoom:1; /* fix ie */
+  }
+#portal-globalnav:after {
+  content:"";
+  clear:both;
+  display:block;
+  visibility:hidden;
+  }
+#portal-globalnav li {
+  display:block;
+  float:left;
+  position:relative;
+  }
+#portal-globalnav li a {
+  display:block;
+  line-height:2em;
+  padding:1px 1em 21px;
+  }
+#portal-globalnav li.selected a {
+  background-color:#205C90;
+  color:#fff;
+  }
+#portal-globalnav li a span {
+  cursor:pointer; /* fix ie */
+  display:block; /* fix ie */
+  white-space: normal;
+  }
+
+/*----- DropDown -----*/
+#portal-globalnav li ul {
+  display:none;
+  left:0;
+  position:absolute;
+  top:100%;
+  z-index:1000;
+  }
+#portal-globalnav li:hover > ul {
+  display:block;
+  }
+#portal-globalnav ul li {
+  float:none;
+  margin:0;
+  }
+#portal-globalnav ul li a {
+  background-color:#ddd;
+  border-top:1px solid #fff;
+  height:auto;
+  padding:0.5em 1.5em 0.5em 1em;
+  vertical-align:top;
+  width:12em;
+  }
+#portal-globalnav li.selected ul li a {
+  background-color:#ddd;
+  color:#205C90;
+  }
+#portal-globalnav li ul ul {
+  top:0;
+  left:100%;
+  }
+#portal-globalnav ul li a.hasChildrens {
+  background-image:url(++resource++quintagroup.dropdownmenu.images/ddm-pointer.gif);
+  background-position:100% 50%;
+  background-repeat:no-repeat;
+  background-color:#ddd;
+  }
+#portal-globalnav ul li a.hasChildrens:hover {
+  background-image:url(++resource++quintagroup.dropdownmenu.images/ddm-pointer.gif);
+  background-position:100% 50%;
+  background-repeat:no-repeat;
+  background-color:#205C90;
+  }
+#portal-globalnav:hover li:hover > a {
+  background-color:#205C90;
+  color:#fff;
+  }
+#portal-globalnav:hover li:hover ul > a {
+  background-color:#ddd;
+  color:#205C90;
+  }
+
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/templates/sections.pt
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/templates/sections.pt	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/templates/sections.pt	(revision 3460)
@@ -0,0 +1,9 @@
+<tal:tabs tal:define="menu view/createMenu"
+          tal:condition="menu"
+          i18n:domain="plone">
+    <ul id="portal-globalnav">
+        <li tal:replace="structure menu">
+            DropDown Menu
+        </li>
+    </ul>
+</tal:tabs>
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/templates/sections_recurse.pt
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/templates/sections_recurse.pt	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/templates/sections_recurse.pt	(revision 3460)
@@ -0,0 +1,45 @@
+<tal:master define="level options/level|python:0;
+                    children options/children | nothing;
+                    plonefour view/is_plone_four"
+            i18n:domain="plone">
+
+<metal:main define-macro="sections_main">
+<tal:navitem repeat="node children">
+<li tal:define="show_children   node/show_children;
+                children        node/children;
+                item_url        node/getURL;
+                item_icon       node/item_icon;
+                is_current      node/currentItem;
+                is_in_path      node/currentParent;
+                li_curr_class   python:is_current and 'selected' or '';
+                li_extr_class   python:(is_in_path and not is_current) and 'selected' or '';
+                li_extr_class   python:(not (is_in_path or is_current)) and li_extr_class + 'plain' or li_extr_class;
+                item_type       node/normalized_portal_type | nothing;
+                li_class string:${li_curr_class}${li_extr_class};
+                li_class python:children and li_class or li_class"
+    tal:attributes="class string:$li_class">
+
+    <tal:level define="show_icons view/conf/show_icons;
+                       a_class python:children and 'hasChildrens' or ''">
+
+    <a tal:attributes="href python:item_url;
+                       title node/Description;
+                       class string:${a_class}">
+        <img tal:condition="python: show_icons and not plonefour"
+             tal:replace="structure item_icon/html_tag | nothing" />
+        <span tal:content="node/Title"
+              tal:attributes="class python: plonefour and show_icons and item_type and 'contenttype-'+ item_type or nothing">Selected Item Title</span>
+    </a>
+
+    <ul tal:attributes="class python:'globalSectionsLevel'+str(level)"
+        tal:condition="python: len(children) > 0 and show_children">
+        <li tal:replace="structure python:view.recurse(children=children, level=level+1)">
+            SubMenu
+        </li>
+    </ul>
+    </tal:level>
+
+</li>
+</tal:navitem>
+</metal:main>
+</tal:master>
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/viewlets.py
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/viewlets.py	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/browser/viewlets.py	(revision 3460)
@@ -0,0 +1,288 @@
+# -*- coding: utf-8 -*-
+from Acquisition import aq_inner
+
+from zope.component import getMultiAdapter
+
+from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
+from Products.CMFCore.utils import getToolByName
+from Products.CMFCore.interfaces import IAction, IActionCategory
+from Products.CMFCore.ActionInformation import ActionInfo
+from Products.CMFPlone.utils import versionTupleFromString
+
+from plone.memoize.instance import memoize
+from plone.memoize.compress import xhtmlslimmer
+from plone.app.layout.viewlets import common
+from plone.app.layout.navigation.navtree import buildFolderTree
+from plone.app.layout.navigation.interfaces import INavtreeStrategy
+
+from quintagroup.dropdownmenu.browser.menu import DropDownMenuQueryBuilder
+from quintagroup.dropdownmenu.util import getDropDownMenuSettings
+
+from time import time
+from plone.memoize import ram
+import copy
+
+
+def menu_cache_key(f, view):
+    # menu cache key conssits of:
+    # - selected item not only top tab
+    # - site can be accessed on different domains
+    # - language is important for multilingua sites
+
+    portal_state = getMultiAdapter((view.context, view.request),
+                                   name=u'plone_portal_state')
+    site_len = len(portal_state.navigation_root_path().split('/'))
+    content_path = view.context.getPhysicalPath()[site_len:]
+    if view.conf.content_tabs_level > 0:
+        content_path = content_path[:view.conf.content_tabs_level]
+    path_key = view.request.physicalPathToURL(content_path)
+
+    language = portal_state.locale().getLocaleID()
+
+    # Cache for five minutes. Note that the HTTP RAM-cache
+    # typically purges entries after 60 minutes.
+    return view.__name__ + \
+           path_key + \
+           language + \
+           str(time() // (60 * 5))
+
+
+# we are caching the menu structure built out of portal_actions tool
+# this cache key does not take in account expressions and roles settings
+def tabs_cache_key(f, view, site_url):
+    return site_url + str(time() // (60 * 60))
+
+
+def dropdowncache(f):
+    def func(view):
+        portal_state = getMultiAdapter((view.context, view.request),
+                                        name=u'plone_portal_state')
+        # it is impossible to reliably cache entire rendered menu generated
+        # with potral actions strategy.
+        if not view.conf.enable_caching or view.conf.show_actions_tabs or \
+           (not portal_state.anonymous() and \
+                view.conf.caching_strategy == 'anonymous'):
+            return f(view)
+        return ram.cache(menu_cache_key)(f)(view)
+    return func
+
+
+def tabscache(f):
+    def func(view, site_url):
+        if not view.conf.enable_caching:
+            return f(view, site_url)
+        return ram.cache(tabs_cache_key)(f)(view, site_url)
+    return func
+
+
+class GlobalSectionsViewlet(common.GlobalSectionsViewlet):
+    index = ViewPageTemplateFile('templates/sections.pt')
+    recurse = ViewPageTemplateFile('templates/sections_recurse.pt')
+
+    def update(self):
+        # we may need some previously defined variables
+        #super(GlobalSectionsViewlet, self).update()
+
+        # prepare to gather portal tabs
+        context = aq_inner(self.context)
+        self.conf = self._settings()
+        self.tool = getToolByName(context, 'portal_actions')
+        self.site_url = getToolByName(context, 'portal_url')()
+        self.context_state = getMultiAdapter((self.context, self.request),
+                                              name="plone_context_state")
+        self.context_url = self.context_state.is_default_page() and \
+            '/'.join(self.context.absolute_url().split('/')[:-1]) or \
+            self.context.absolute_url()
+
+        self.cat_sufix = self.conf.nested_category_sufix or ''
+        self.cat_prefix = self.conf.nested_category_prefix or ''
+
+    @property
+    def portal_tabs(self):
+        tabs = []
+
+        # fetch actions-based tabs?
+        if self.conf.show_actions_tabs:
+            tabs.extend(self._actions_tabs())
+
+        # fetch content structure-based tabs?
+        if self.conf.show_content_tabs:
+            # put content-based actions before content structure-based ones?
+            if self.conf.content_before_actions_tabs:
+                tabs = self._content_tabs() + tabs
+            else:
+                tabs.extend(self._content_tabs())
+
+        return tabs
+
+    def _actions_tabs(self):
+        """Return tree of tabs based on portal_actions tool configuration"""
+        conf = self.conf
+        tool = self.tool
+
+        # check if we have required root actions category inside tool
+        if conf.actions_category not in tool.objectIds():
+            return []
+        listtabs = []
+        res, listtabs = self.prepare_tabs(self.site_url)
+        res = copy.deepcopy(res)
+        self.tabs = listtabs
+
+        # if there is no custom menu in portal tabs return
+        if not listtabs:
+            return []
+
+        current_item = -1
+        delta = 1000
+        for info in listtabs:
+            if  self.context_url.startswith(info['url']) and \
+                len(self.context_url) - len(info['url']) < delta:
+                delta = len(self.context_url) - len(info['url'])
+                current_item = listtabs.index(info)
+        self.id_chain = []
+
+        if current_item > -1 and current_item < len(listtabs) and \
+            (listtabs[current_item]['url'] != self.site_url or \
+            listtabs[current_item]['url'] == self.site_url and \
+            self.context_url == self.site_url):
+
+            self.mark_active(listtabs[current_item]['id'],
+                             listtabs[current_item]['url'])
+
+        self._activate(res)
+        return res
+
+    @tabscache
+    def prepare_tabs(self, site_url):
+        def normalize_actions(category, object, level, parent_url=None):
+            """walk through the tabs dictionary and build list of all tabs"""
+            tabs = []
+            for info in self._actionInfos(category, object):
+                icon = info['icon'] and '<img src="%s" />' % info['icon'] or ''
+                children = []
+                bottomLevel = self.conf.actions_tabs_level
+                if bottomLevel < 1 or level < bottomLevel:
+                    # try to find out appropriate subcategory
+                    subcat_id = self.cat_prefix + info['id'] + self.cat_sufix
+                    if subcat_id != info['id'] and \
+                       subcat_id in category.objectIds():
+                        subcat = category._getOb(subcat_id)
+                        if IActionCategory.providedBy(subcat):
+                            children = normalize_actions(subcat, object,
+                                                         level + 1,
+                                                         info['url'])
+
+                parent_id = category['id'].replace(self.cat_prefix,
+                                '').replace(self.cat_sufix, '')
+                tab = {'id': info['id'],
+                   'title': info['title'],
+                   'url': info['url'],
+                   'parent': (parent_id, parent_url)}
+                tabslist.append(tab)
+
+                tab = {'id': info['id'],
+                       'Title': info['title'],
+                       'Description': info['description'],
+                       'getURL': info['url'],
+                       'show_children': len(children) > 0,
+                       'children': children,
+                       'currentItem': False,
+                       'currentParent': False,
+                       'item_icon': {'html_tag': icon},
+                       'normalized_review_state': 'visible'}
+                tabs.append(tab)
+            return tabs
+        tabslist = []
+        tabs = normalize_actions(self.tool._getOb(self.conf.actions_category),
+                                 aq_inner(self.context), 0)
+        return tabs, tabslist
+
+    def _activate(self, res):
+        """Mark selected chain in the tabs dictionary"""
+        for info in res:
+            if info['getURL'] in self.id_chain:
+                info['currentItem'] = True
+                info['currentParent'] = True
+                if info['children']:
+                    self._activate(info['children'])
+
+    def mark_active(self, current_id, url):
+        for info in self.tabs:
+            if info['id'] == current_id and info['url'] == url:
+                self.mark_active(info['parent'][0], info['parent'][1])
+                self.id_chain.append(info['url'])
+
+    def _actionInfos(self, category, object, check_visibility=1,
+                     check_permissions=1, check_condition=1, max=-1):
+        """Return action infos for a given category"""
+        ec = self.tool._getExprContext(object)
+        actions = [ActionInfo(action, ec) for action in category.objectValues()
+                    if IAction.providedBy(action)]
+
+        action_infos = []
+        for ai in actions:
+            if check_visibility and not ai['visible']:
+                continue
+            if check_permissions and not ai['allowed']:
+                continue
+            if check_condition and not ai['available']:
+                continue
+            action_infos.append(ai)
+            if max + 1 and len(action_infos) >= max:
+                break
+        return action_infos
+
+    def _content_tabs(self):
+        """Return tree of tabs based on content structure"""
+        context = aq_inner(self.context)
+
+        queryBuilder = DropDownMenuQueryBuilder(context)
+        strategy = getMultiAdapter((context, None), INavtreeStrategy)
+        # XXX This works around a bug in plone.app.portlets which was
+        # fixed in http://dev.plone.org/svn/plone/changeset/18836
+        # When a release with that fix is made this workaround can be
+        # removed and the plone.app.portlets requirement in setup.py
+        # be updated.
+        if strategy.rootPath is not None and strategy.rootPath.endswith("/"):
+            strategy.rootPath = strategy.rootPath[:-1]
+
+        return buildFolderTree(context, obj=context, query=queryBuilder(),
+                               strategy=strategy).get('children', [])
+
+    @memoize
+    def _settings(self):
+        """Fetch dropdown menu settings registry"""
+        return getDropDownMenuSettings(self.context)
+
+    @dropdowncache
+    def createMenu(self):
+        html = self.recurse(children=self.portal_tabs, level=1)
+        return xhtmlslimmer.compress(html).strip('\n')
+
+    def _old_update(self):
+        context_state = getMultiAdapter((self.context, self.request),
+                                        name=u'plone_context_state')
+        actions = context_state.actions()
+        portal_tabs_view = getMultiAdapter((self.context, self.request),
+                                           name='portal_tabs_view')
+        self.portal_tabs = portal_tabs_view.topLevelTabs(actions=actions)
+
+        selectedTabs = self.context.restrictedTraverse('selectedTabs')
+        self.selected_tabs = selectedTabs('index_html',
+                                          self.context,
+                                          self.portal_tabs)
+        self.selected_portal_tab = self.selected_tabs['portal']
+
+    @memoize
+    def is_plone_four(self):
+        """Indicates if we are in plone 4.
+
+        """
+        pm = getToolByName(aq_inner(self.context), 'portal_migration')
+        try:
+            version = versionTupleFromString(pm.getSoftwareVersion())
+        except AttributeError:
+            version = versionTupleFromString(pm.getFileSystemVersion())
+
+        if version:
+            return version[0] == 4
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/configure.zcml
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/configure.zcml	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/configure.zcml	(revision 3460)
@@ -0,0 +1,45 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:five="http://namespaces.zope.org/five"
+    xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
+    i18n_domain="quintagroup.dropdownmenu">
+
+  <!-- This need for QI for possibility to find "uninstall"
+       method in then ./Extensions/install.py external method -->
+  <five:registerPackage package="." />
+
+  <!-- Include configuration for dependencies listed in setup.py -->
+  <include package="plone.app.registry" />
+
+  <!-- Include internal packages -->
+  <include package=".browser" />
+
+  <!-- Register the installation GenericSetup extension profile -->
+  <genericsetup:registerProfile
+      name="default"
+      title="Plone DropDown Menu"
+      description="DropDown Menu Product for Plone"
+      directory="profiles/default"
+      provides="Products.GenericSetup.interfaces.EXTENSION"
+      for="Products.CMFPlone.interfaces.IPloneSiteRoot"
+      />
+
+  <genericsetup:registerProfile
+      name="uninstall"
+      title="Uninstall Plone DropDown Menu"
+      description="Uninstall profile for DropDown Menu Product"
+      directory="profiles/uninstall"
+      provides="Products.GenericSetup.interfaces.EXTENSION"
+      for="Products.CMFPlone.interfaces.IPloneSiteRoot"
+      />
+
+  <genericsetup:importStep
+      name="quintagroup.dropdownmenu.uninstall"
+      title="Plone DropDown Menu Product: miscellaneous uninstallation steps"
+      description="Various uninstallation steps that are not handled by GS import/export handlers."
+      handler="quintagroup.dropdownmenu.setuphandlers.uninstall">
+    <!-- <depends name="skins"/> -->
+  </genericsetup:importStep>
+
+
+</configure>
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/interfaces.py
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/interfaces.py	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/interfaces.py	(revision 3460)
@@ -0,0 +1,100 @@
+# -*- coding: utf-8 -*-
+from zope import schema
+from zope.interface import Interface
+
+from plone.theme.interfaces import IDefaultPloneLayer
+from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm
+
+from quintagroup.dropdownmenu import _
+
+cachings = SimpleVocabulary(
+    [SimpleTerm(value=u'anonymous', title=_(u'Cache only for anonymous')),
+     SimpleTerm(value=u'all', title=_(u'Cache for all users')), ]
+    )
+
+
+class IDropDownMenuLayer(IDefaultPloneLayer):
+    """Request marker installed via browserlayer.xml.
+    """
+
+
+class IDropDownMenuSettings(Interface):
+    """Global dropdown menu settings. This describes records stored in the
+    configuration registry and obtainable via plone.registry.
+    """
+
+    show_icons = schema.Bool(
+        title=_(u"Show tabs icons"),
+        description=_(u"Use this setting to switch on/off icons for menu "
+                      u"items."),
+        default=False)
+
+    show_content_tabs = schema.Bool(
+        title=_(u"Show navigation strategy based dropdown menu"),
+        description=_(u"Use this setting to switch on/off navigation "
+                      u"strategy built dropdown menu"),
+        default=True)
+
+    show_nonfolderish_tabs = schema.Bool(
+        title=_(u"Show non-folderish menu items"),
+        description=_(u"Use this setting to switch on/off non-folderish "
+                      u"objects in navigation strategy based dropdown menu"),
+        default=True)
+
+    content_before_actions_tabs = schema.Bool(
+        title=_(u"Show content tabs before portal_actions tabs"),
+        description=_(u""),
+        default=False)
+
+    content_tabs_level = schema.Int(
+        title=_(u"Navigation strategy dropdown menu depth"),
+        description=_(u"How many levels folders to list after the "
+                      u"top level."),
+        default=0)
+
+    show_actions_tabs = schema.Bool(
+        title=_(u"Show actions tabs"),
+        description=_(u"Use this setting to enable/disable portal_actions "
+                      u"based dropdown menu"),
+        default=True)
+
+    actions_tabs_level = schema.Int(
+        title=_(u"Actions dropdown menu depth"),
+        description=_(u"How many levels of portal_actions to list after the "
+                      u"top level."),
+        default=0)
+
+    actions_category = schema.TextLine(
+        title=_(u"Root portal actions category"),
+        description=_(u"Root category id of portal_actions based dropdown "
+                      u"menu tree"),
+        default=u"portal_tabs")
+
+    nested_category_prefix = schema.TextLine(
+        title=_(u"Nested category prefix"),
+        description=_(u"Prefix of category id, used to bind category "
+                      u"with action"),
+        default=u"",
+        required=False)
+
+    nested_category_sufix = schema.TextLine(
+        title=_(u"Nested category sufix"),
+        description=_(u"Sufix of category id, used to bind category "
+                      u"with action"),
+        default=u"_sub",
+        required=False)
+
+    enable_caching = schema.Bool(
+        title=_(u"Enable menu caching"),
+        description=_(u"Caching of the menu viewlet improves page rendering "
+                      u"speed."),
+        default=True
+        )
+
+    caching_strategy = schema.Choice(
+    title=_(u"Select caching strategy"),
+    description=_(u"Caching strategy defines how the cache key will be built."
+                 ),
+    default="anonymous",
+    vocabulary=cachings
+    )
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/profiles/default/browserlayer.xml
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/profiles/default/browserlayer.xml	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/profiles/default/browserlayer.xml	(revision 3460)
@@ -0,0 +1,6 @@
+<layers>
+    <layer
+        name="quintagroup.dropdownmenu"
+        interface="quintagroup.dropdownmenu.interfaces.IDropDownMenuLayer"
+        />
+</layers>
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/profiles/default/controlpanel.xml
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/profiles/default/controlpanel.xml	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/profiles/default/controlpanel.xml	(revision 3460)
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<object name="portal_controlpanel" xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+    i18n:domain="quintagroup.dropdownmenu" purge="False">
+
+ <configlet title="DropDown Menu" action_id="dropdownmenu" appId="quintagroup.dropdownmenu"
+     category="Products" condition_expr="" url_expr="string:${portal_url}/@@dropdownmenu-settings"
+     visible="True" i18n:attributes="title">
+   <permission>Manage portal</permission>
+ </configlet>
+
+</object>
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/profiles/default/cssregistry.xml
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/profiles/default/cssregistry.xml	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/profiles/default/cssregistry.xml	(revision 3460)
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<object name="portal_css" meta_type="Stylesheets Registry">
+ <stylesheet title="DropDown Menu" cacheable="True" compression="safe" cookable="True"
+     enabled="1" expression="" id="++resource++drop_down.css" media="screen"
+     rel="stylesheet" rendering="import"/>
+</object>
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/profiles/default/metadata.xml
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/profiles/default/metadata.xml	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/profiles/default/metadata.xml	(revision 3460)
@@ -0,0 +1,6 @@
+<metadata>
+ <version>1.2.8</version>
+ <dependencies>
+  <dependency>profile-plone.app.registry:default</dependency>
+ </dependencies>
+</metadata>
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/profiles/default/registry.xml
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/profiles/default/registry.xml	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/profiles/default/registry.xml	(revision 3460)
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<registry>
+ <records interface="quintagroup.dropdownmenu.interfaces.IDropDownMenuSettings" />
+</registry>
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/profiles/uninstall/cssregistry.xml
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/profiles/uninstall/cssregistry.xml	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/profiles/uninstall/cssregistry.xml	(revision 3460)
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<object name="portal_css">
+ <stylesheet id="++resource++drop_down.css" remove="True"/>
+</object>
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/setuphandlers.py
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/setuphandlers.py	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/setuphandlers.py	(revision 3460)
@@ -0,0 +1,54 @@
+import logging
+from zope.component import queryUtility
+from plone.registry.interfaces import IRegistry
+
+from Products.CMFCore.utils import getToolByName
+
+from quintagroup.dropdownmenu.interfaces import IDropDownMenuSettings
+from quintagroup.dropdownmenu import PROJECT_NAME, logger
+
+
+def removeConfiglet(site):
+    """ Remove configlet.
+    """
+    conf_id = "dropdownmenu"
+    controlpanel_tool = getToolByName(site, 'portal_controlpanel')
+    if controlpanel_tool:
+        controlpanel_tool.unregisterConfiglet(conf_id)
+        logger.log(logging.INFO, "Unregistered \"%s\" configlet." % conf_id)
+
+
+def cleanupRegistry(site):
+    registry = queryUtility(IRegistry)
+    iprefix = IDropDownMenuSettings.__identifier__ + '.'
+    delrecs = [r for r in registry.records.keys() if r.startswith(iprefix)]
+    map(registry.records.__delitem__, delrecs)
+    logger.log(logging.INFO,
+               "Removed %s items from plone.app.registry" % delrecs)
+
+
+def fixQIUninstallDependencies(site):
+    """Uninstallation procedure of Quickinstaller tool clean-up settings,
+       made by dependent products. Fix this issue.
+    """
+    qi = getToolByName(site, 'portal_quickinstaller')
+    qiprod = getattr(qi, PROJECT_NAME, None)
+    if qiprod:
+        utilities = getattr(qiprod, 'utilities', [])
+        todel = filter(lambda k: not sum(map(
+                    lambda i: PROJECT_NAME in i, k)), utilities)
+        for u in todel:
+            uidx = utilities.index(u)
+            del utilities[uidx]
+
+
+def uninstall(context):
+    """ Do customized uninstallation.
+    """
+    if context.readDataFile('quintagroup_dropdownmenu_uninstall.txt') is None:
+        return
+
+    site = context.getSite()
+    fixQIUninstallDependencies(site)
+    removeConfiglet(site)
+    cleanupRegistry(site)
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/tests/__init__.py
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/tests/__init__.py	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/tests/__init__.py	(revision 3460)
@@ -0,0 +1,1 @@
+#
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/tests/base.py
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/tests/base.py	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/tests/base.py	(revision 3460)
@@ -0,0 +1,89 @@
+from zope.interface import alsoProvides
+
+from AccessControl import getSecurityManager
+from AccessControl.SecurityManagement import setSecurityManager
+
+from Testing import ZopeTestCase as ztc
+from Products.Five import fiveconfigure
+from Products.PloneTestCase import PloneTestCase as ptc
+
+from collective.testcaselayer.ptc import BasePTCLayer, ptc_layer
+
+
+from quintagroup.dropdownmenu import PROJECT_NAME
+from quintagroup.dropdownmenu.interfaces import IDropDownMenuLayer
+
+IPREFIX = 'quintagroup.dropdownmenu.interfaces.IDropDownMenuSettings.'
+
+# This step made in collective.testcaselayer.ptc
+#ptc.setupPloneSite()
+
+
+class NotInstalled(BasePTCLayer):
+    """Initialize the package, without installation into portal
+    """
+    def afterSetUp(self):
+        fiveconfigure.debug_mode = True
+        import quintagroup.dropdownmenu
+        self.loadZCML('configure.zcml', package=quintagroup.dropdownmenu)
+        fiveconfigure.debug_mode = False
+        ztc.installPackage(PROJECT_NAME)
+
+
+class Installed(BasePTCLayer):
+    """ Install product into the portal
+    """
+    def afterSetUp(self):
+        self.addProduct(PROJECT_NAME)
+
+
+class UnInstalled(BasePTCLayer):
+    """ UnInstall product from the portal
+    """
+    def afterSetUp(self):
+        sm = getSecurityManager()
+        self.loginAsPortalOwner()
+        try:
+            qi = self.portal.portal_quickinstaller
+            qi.uninstallProducts(products=[PROJECT_NAME, ])
+            #self._refreshSkinData()
+        finally:
+            setSecurityManager(sm)
+
+NotInstalledLayer = NotInstalled([ptc_layer, ])
+InstalledLayer = Installed([NotInstalledLayer, ])
+UnInstalledLayer = UnInstalled([InstalledLayer, ])
+
+
+class TestCaseNotInstalled(ptc.PloneTestCase):
+    layer = NotInstalledLayer
+
+
+class TestCase(ptc.PloneTestCase):
+    layer = InstalledLayer
+
+    def afterSetUp(self):
+        # mark request with our browser layer
+        super(TestCase, self).afterSetUp()
+        alsoProvides(self.app.REQUEST, IDropDownMenuLayer)
+
+
+class TestCaseUnInstalled(ptc.PloneTestCase):
+    layer = UnInstalledLayer
+
+
+class FunctionalTestCaseNotInstalled(ptc.FunctionalTestCase):
+    layer = NotInstalledLayer
+
+
+class FunctionalTestCase(ptc.FunctionalTestCase):
+    layer = InstalledLayer
+
+    def afterSetUp(self):
+        # mark request with our browser layer
+        super(FunctionalTestCase, self).afterSetUp()
+        alsoProvides(self.app.REQUEST, IDropDownMenuLayer)
+
+
+class FunctionalTestCaseUnInstalled(ptc.FunctionalTestCase):
+    layer = UnInstalledLayer
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/tests/test_controlpanel.py
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/tests/test_controlpanel.py	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/tests/test_controlpanel.py	(revision 3460)
@@ -0,0 +1,103 @@
+# -*- coding: utf-8 -*-
+import unittest
+from plone.registry import Registry
+
+from base import TestCase
+from base import IPREFIX
+
+from Products.CMFCore.utils import getToolByName
+from quintagroup.dropdownmenu.interfaces import IDropDownMenuSettings
+
+
+class RegistryTest(TestCase):
+
+    def afterSetUp(self):
+        # Set up the registry
+        super(RegistryTest, self).afterSetUp()
+        self.registry = Registry()
+        self.registry.registerInterface(IDropDownMenuSettings)
+
+    def test_dropdownmenu_in_controlpanel(self):
+        # Check if dropdownmenu is in the control panel
+        self.controlpanel = getToolByName(self.portal, "portal_controlpanel")
+        self.failUnless('dropdownmenu' in [a.getAction(self)['id']
+                            for a in self.controlpanel.listActions()])
+
+    def test_show_icons(self):
+        # Check show_icons record
+        self.registry.records[IPREFIX + 'show_icons']
+
+        self.failUnless('show_icons' in IDropDownMenuSettings)
+        self.assertEquals(self.registry[IPREFIX + 'show_icons'], False)
+
+    def test_show_content_tabs(self):
+        # Check show_content_tabs record
+        self.registry.records[IPREFIX + 'show_content_tabs']
+
+        self.failUnless('show_content_tabs' in IDropDownMenuSettings)
+        self.assertEquals(self.registry[IPREFIX + 'show_content_tabs'], True)
+
+    def test_show_nonfolderish_tabs(self):
+        # Check show_nonfolderish_tabs record
+        self.registry.records[IPREFIX + 'show_nonfolderish_tabs']
+
+        self.failUnless('show_nonfolderish_tabs' in IDropDownMenuSettings)
+        self.assertEquals(self.registry[IPREFIX + 'show_nonfolderish_tabs'],
+                          True)
+
+    def test_content_before_actions_tabs(self):
+        # Check content_before_actions_tabs record
+        self.registry.records[IPREFIX + 'content_before_actions_tabs']
+
+        self.failUnless('content_before_actions_tabs' in IDropDownMenuSettings)
+        self.assertEquals(self.registry[
+            IPREFIX + 'content_before_actions_tabs'], False)
+
+    def test_content_tabs_level(self):
+        # Check content_tabs_level record
+        self.registry.records[IPREFIX + 'content_tabs_level']
+
+        self.failUnless('content_tabs_level' in IDropDownMenuSettings)
+        self.assertEquals(self.registry[IPREFIX + 'content_tabs_level'], 0)
+
+    def test_show_actions_tabs(self):
+        # Check show_actions_tabs record
+        self.registry.records[IPREFIX + 'show_actions_tabs']
+
+        self.failUnless('show_actions_tabs' in IDropDownMenuSettings)
+        self.assertEquals(self.registry[IPREFIX + 'show_actions_tabs'], True)
+
+    def test_actions_tabs_level(self):
+        # Check actions_tabs_level record
+        self.registry.records[IPREFIX + 'actions_tabs_level']
+
+        self.failUnless('actions_tabs_level' in IDropDownMenuSettings)
+        self.assertEquals(self.registry[IPREFIX + 'actions_tabs_level'], 0)
+
+    def test_actions_category(self):
+        # Check actions_category record
+        self.registry.records[IPREFIX + 'actions_category']
+
+        self.failUnless('actions_category' in IDropDownMenuSettings)
+        self.assertEquals(self.registry[IPREFIX + 'actions_category'],
+                          u"portal_tabs")
+
+    def test_nested_category_prefix(self):
+        # Check nested_category_prefix record
+        self.registry.records[IPREFIX + 'nested_category_prefix']
+
+        self.failUnless('nested_category_prefix' in IDropDownMenuSettings)
+        self.assertEquals(self.registry[IPREFIX + 'nested_category_prefix'],
+                          u"")
+
+    def test_nested_category_sufix(self):
+        # Check nested_category_sufix record
+        self.registry.records[IPREFIX + 'nested_category_sufix']
+
+        self.failUnless('nested_category_sufix' in IDropDownMenuSettings)
+        self.assertEquals(self.registry[IPREFIX + 'nested_category_sufix'],
+                          u"_sub")
+
+
+def test_suite():
+    return unittest.defaultTestLoader.loadTestsFromName(__name__)
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/tests/test_docs.py
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/tests/test_docs.py	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/tests/test_docs.py	(revision 3460)
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+import unittest
+
+#from zope.testing import doctestunit
+#from zope.component import testing
+
+
+def test_suite():
+    return unittest.TestSuite([
+
+        # Unit tests
+        #doctestunit.DocFileSuite(
+        #    'README.txt', package='quintagroup.dropdownmenu',
+        #    setUp=testing.setUp, tearDown=testing.tearDown),
+
+        #doctestunit.DocTestSuite(
+        #    module='quintagroup.dropdownmenu.mymodule',
+        #    setUp=testing.setUp, tearDown=testing.tearDown),
+
+
+        # Integration tests that use PloneTestCase
+        #ztc.ZopeDocFileSuite(
+        #    'menu.txt', package='quintagroup.dropdownmenu',
+        #    test_class=TestCase),
+
+        #ztc.FunctionalDocFileSuite(
+        #    'browser.txt', package='quintagroup.dropdownmenu',
+        #    test_class=TestCase),
+
+        ])
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/tests/test_installation.py
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/tests/test_installation.py	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/tests/test_installation.py	(revision 3460)
@@ -0,0 +1,99 @@
+#
+# Test product's installation
+#
+from zope.component import queryUtility
+from plone.registry.interfaces import IRegistry
+from plone.browserlayer import utils as blutils
+
+from Products.CMFCore.utils import getToolByName
+
+from quintagroup.dropdownmenu.tests.base import TestCase, TestCaseUnInstalled
+from quintagroup.dropdownmenu.tests.base import IPREFIX
+
+from quintagroup.dropdownmenu import PROJECT_NAME
+from quintagroup.dropdownmenu.interfaces import IDropDownMenuLayer
+
+CSS_RESOURCES = ["++resource++drop_down.css", ]
+DEPENDENCIES = ["plone.app.registry", ]
+CONFIGLETS = ["dropdownmenu", ]
+#REGISTRY_INTERFACE="quintagroup.dropdownmenu.interfaces.IDropDownMenuSettings"
+
+
+class TestInstallation(TestCase):
+
+    def testInstalled(self):
+        qi = self.portal.portal_quickinstaller
+        self.assertTrue(qi.isProductInstalled(PROJECT_NAME),
+            '%s is not installed.' % PROJECT_NAME)
+
+    def testInstalledDependencies(self):
+        cp = self.portal.portal_controlpanel
+        configlets = [ai['id'] for ai in cp.listActionInfos(
+                                             check_permissions=0)]
+        self.assertTrue([1 for ai in configlets if ai == "plone.app.registry"],
+                'Not installed required plone.app.registry product.')
+
+    def testStyles(self):
+        """ Test styles registration."""
+        cssreg = getToolByName(self.portal, "portal_css")
+        for res in CSS_RESOURCES:
+            self.assertNotEqual(cssreg.getResource(res), None)
+
+    def testConfiglet(self):
+        cp = self.portal.portal_controlpanel
+        configlets = [ai['id'] for ai in cp.listActionInfos(
+                                             check_permissions=0)]
+        for cid in CONFIGLETS:
+            self.assertTrue([1 for ai in configlets if ai == cid],
+                'No "%s" configlet added to plone control panel' % cid)
+
+    def testBrowserLayer(self):
+        self.assert_(IDropDownMenuLayer in blutils.registered_layers(),
+                     "Not registered 'IDropDownMenuLayer' browser layer")
+
+    def testRegistry(self):
+        registry = queryUtility(IRegistry)
+        afield = "show_content_tabs"
+        self.assertTrue(registry.records.get(IPREFIX + afield, None),
+            "Not registered '%s' registry interface" % IPREFIX)
+
+
+class TestUninstallation(TestCaseUnInstalled):
+
+    def testUninstalled(self):
+        qi = self.portal.portal_quickinstaller
+        self.assertFalse(qi.isProductInstalled(PROJECT_NAME),
+            '%s not uninstalled.' % PROJECT_NAME)
+
+    def testStyles(self):
+        """ Test styles registration."""
+        cssreg = getToolByName(self.portal, "portal_css")
+        for res in CSS_RESOURCES:
+            self.assertEqual(cssreg.getResource(res), None)
+
+    def testConfiglet(self):
+        cp = self.portal.portal_controlpanel
+        configlets = [ai['id'] for ai in cp.listActionInfos(
+                                            check_permissions=0)]
+        for cid in CONFIGLETS:
+            self.assertFalse([1 for ai in configlets if ai == cid],
+                '"%s" configlet not uninstalled '\
+                'from plone control panel' % cid)
+
+    def testBrowserLayer(self):
+        self.assertFalse(IDropDownMenuLayer in blutils.registered_layers(),
+                     "Not unregistered 'IDropDownMenuLayer' browser layer")
+
+    def testRegistry(self):
+        registry = queryUtility(IRegistry)
+        afield = "show_content_tabs"
+        self.assertFalse(registry.records.get(IPREFIX + afield, None),
+            "Not unregistered '%s' registry interface" % IPREFIX)
+
+
+def test_suite():
+    from unittest import TestSuite, makeSuite
+    suite = TestSuite()
+    suite.addTest(makeSuite(TestInstallation))
+    suite.addTest(makeSuite(TestUninstallation))
+    return suite
Index: /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/util.py
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/util.py	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/quintagroup/dropdownmenu/util.py	(revision 3460)
@@ -0,0 +1,59 @@
+# -*- coding: utf-8 -*-
+# Miscellaneous functions to use from inside different parts of this package.
+
+from zope.component import getUtility
+
+from Products.CMFCore.utils import getToolByName
+
+from plone.registry.recordsproxy import RecordsProxy, _marker
+from plone.registry.interfaces import IRegistry
+
+from quintagroup.dropdownmenu.interfaces import IDropDownMenuSettings
+
+
+PROP_MAPPING = {
+    'show_content_tabs': 'disable_folder_sections',
+    'show_nonfolderish_tabs': 'disable_nonfolderish_sections',
+}
+
+
+def getDropDownMenuSettings(context):
+    """Return dropdown menu settings"""
+    registry = getUtility(IRegistry)
+    return DropDownMenuRecordsProxy(context, registry, IDropDownMenuSettings,
+                                    omitted=())
+
+
+class DropDownMenuRecordsProxy(RecordsProxy):
+    """Override a few dropdown menu specific settings to get from portal
+    properties instead of taking them from plone.registry components"""
+
+    def __init__(self, context, registry, schema, omitted=()):
+        # override initialization to pass context for further purposes;
+        # yes, I know, this is badly to depend on context in utilities,
+        # but I haven't come up with some better way to proxy
+        # plone.registry yet skip __setattr__
+        self.__dict__['__context__'] = context
+        super(DropDownMenuRecordsProxy, self).__init__(registry, schema,
+                                                       omitted)
+
+    def __getattr__(self, name):
+        if name not in self.__schema__:
+            raise AttributeError(name)
+        value = _marker
+        if name in ('show_content_tabs', 'show_nonfolderish_tabs'):
+            context = self.__context__
+            prop_tool = getToolByName(context, 'portal_properties')
+            if 'site_properties' in prop_tool.objectIds():
+                sheet = prop_tool._getOb('site_properties')
+                if sheet.hasProperty(PROP_MAPPING[name]):
+                    value = not sheet.getProperty(PROP_MAPPING[name])
+        else:
+            value = self.__registry__.get(self.__prefix__ + name, _marker)
+        if value is _marker:
+            value = self.__schema__[name].missing_value
+        return value
+
+    def __repr__(self):
+        return "<DropDownMenuRecordsProxy for %s>" % \
+               self.__schema__.__identifier__
Index: /quintagroup.dropdownmenu/tags/1.2.9/setup.cfg
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/setup.cfg	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/setup.cfg	(revision 3460)
@@ -0,0 +1,2 @@
+[egg_info]
+tag_build = dev
Index: /quintagroup.dropdownmenu/tags/1.2.9/setup.py
===================================================================
--- /quintagroup.dropdownmenu/tags/1.2.9/setup.py	(revision 3460)
+++ /quintagroup.dropdownmenu/tags/1.2.9/setup.py	(revision 3460)
@@ -0,0 +1,43 @@
+from setuptools import setup, find_packages
+import os
+
+version = '1.2.9'
+
+tests_require = ['zope.testing',
+               'collective.testcaselayer']
+
+setup(name='quintagroup.dropdownmenu',
+      version=version,
+      description="Multilevel portal dropdown menu for Plone sites.",
+      long_description=open("README.txt").read() + "\n" +
+                       open(os.path.join("docs", "HISTORY.txt")).read(),
+      classifiers=[
+        "Framework :: Plone",
+        "Programming Language :: Python",
+        "License :: OSI Approved :: GNU General Public License (GPL)",
+        "Operating System :: OS Independent",
+        "Topic :: Software Development :: Libraries :: Python Modules",
+        ],
+      keywords='web plone menu',
+      author='Quintagroup',
+      author_email='support@quintagroup.com',
+      url='http://quintagroup.com/services/plone-development/products/'
+          'quintagroup.dropdownmenu',
+      license='GPL',
+      packages=find_packages(exclude=['ez_setup']),
+      namespace_packages=['quintagroup'],
+      include_package_data=True,
+      zip_safe=False,
+      install_requires=[
+          'setuptools',
+          'plone.registry',
+          'plone.app.registry',
+      ],
+      tests_require=tests_require,
+      extras_require=dict(tests=tests_require),
+      test_suite='quintagroup.dropdownmenu.tests',
+      entry_points="""
+      [z3c.autoinclude.plugin]
+      target = plone
+      """,
+      )
