I like programming in Python. I like learning about it, I like using it, and so I wish to share it.

Friday, July 10, 2009

ArgoUML & ArchGenXML Howto

For a more detailed understanding of these instructions, go to it's source at the Plone docs.
These instructions has been tested with ArgoUML 0.26.2 and 0.28.



ArchGenXML Buildout



The recommended way now to get the ArchGenXML product is through a buildout.


  1. Create a fresh directory and go into it.



  2. In that directory copy the bootstrap.py file.




  3. Then write a buildout.cfg file with the following contents:



    [buildout]
    parts =
    archgenxml
    [archgenxml]
    recipe = zc.recipe.egg:scripts
    eggs = archgenxml


  4. Finally bootstap buildout and run it:



    $ python bootstrap.py
    $ bin/buildout








Generate ArgoUML Profile


Then you should generate the argouml profile by doing:



$ bin/agx_argouml_profile

That would create the archgenxml_profile.xmi.




Configure ArgoUML to use the generated profile



The steps are:



  1. Open argouml

  2. Go to the menu Edit->Settings. Go to the Profiles tab.

  3. Click on the Add button and select the folder where you generated the profile (Just now we generated it at the root of the archgenxml product).

  4. Click OK.

  5. Restart argouml (Close argouml and open it again).

  6. Go back to Edit->Settings->Profiles page and AGXProfile should be available in the Available Profiles field. Select it into the Default Profiles and click ok and again restart argouml.

  7. Now your default argouml settings are ready.







Use AGXProfile for your projects



To use the AGXProfile for your project, the steps are:


  1. Click the Project Properties Button (4th one from the left on the Toolbar)

  2. Click the Profiles tab

  3. Remove UML 1.4 from Active Profile (The AGXProfile should already be in the Active Profile field)

  4. Click ok and you're ready to rock and roll




Saturday, July 4, 2009

2 Level Navigation In Plone 3

This implementation is based on the Two Level Navigation In Plone. In the original how-to, the author customized global_sections template which has been deprecated for Plone 3 onwards. This how-to shows how to do it by modifying the viewlet for the navigation based on a theme product. For more details about modifying the viewlet, please refer to the Overriding Template View how-to.
Step By Step

These are the steps to implement it:

1. First you have to have your theme product ready. If you do not know how to do this then please refer to How To Create a Plone 3 Theme Product on the Filesystem. For this example let's assume the theme product is inigo.theme.
2. Then inside your theme product you should have a directory called viewlet. I used this method with the idea that any modifications for the viewlets which you would like to do for your theme should be put in here.
3. In the viewlet folder you should have 4 file:
* __init__.py
* common.py
* configure.zcml
* sections.pt
4. Contents of those files should be:
* __init__.py : empty file. Should be there just so that you could package the folder as part of your egg
* common.py :


from zope.interface import implements, alsoProvides
from zope.component import getMultiAdapter
from zope.viewlet.interfaces import IViewlet
from zope.deprecation.deprecation import deprecate

from plone.app.layout.globals.interfaces import IViewView

from AccessControl import getSecurityManager
from Acquisition import aq_base, aq_inner
from Products.CMFPlone.utils import safe_unicode
from Products.Five.browser import BrowserView
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
from Products.CMFCore.utils import getToolByName
from Products.CMFPlone import utils
from Products.CMFPlone.browser.navigation import get_url,get_id,get_view_url
from cgi import escape
from urllib import quote_plus
from plone.app.layout.navigation.root import getNavigationRoot

class ViewletBase(BrowserView):
""" Base class with common functions for link viewlets.
"""
implements(IViewlet)

def __init__(self, context, request, view, manager):
super(ViewletBase, self).__init__(context, request)
self.__parent__ = view
self.context = context
self.request = request
self.view = view
self.manager = manager

@property
@deprecate("Use site_url instead. ViewletBase.portal_url will be removed in Plone 4")
def portal_url(self):
return self.site_url


def update(self):
self.portal_state = getMultiAdapter((self.context, self.request),
name=u'plone_portal_state')
self.site_url = self.portal_state.portal_url()

def render(self):
# defer to index method, because that's what gets overridden by the template ZCML attribute
return self.index()

def index(self):
raise NotImplementedError(
'`index` method must be implemented by subclass.')

class GlobalSectionsViewlet(ViewletBase):
index = ViewPageTemplateFile('sections.pt')

def 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']

for tab in self.portal_tabs:
if tab['id']!='Members':
tab['subtab']=self.getsubtab(self.context,tab)
else:
tab['subtab']=[]

def getsubtab(self,context,tab):
query={}
result=[]
portal_properties = getToolByName(context, 'portal_properties')
portal_catalog = getToolByName(context, 'portal_catalog')
navtree_properties = getattr(portal_properties, 'navtree_properties')
site_properties = getattr(portal_properties, 'site_properties')

rootPath = getNavigationRoot(context)
dpath='/'.join([rootPath,tab['id']])
query['path'] = {'query' : dpath, 'depth' : 1}

query['portal_type'] = utils.typesToList(context)

sortAttribute = navtree_properties.getProperty('sortAttribute', None)
if sortAttribute is not None:
query['sort_on'] = sortAttribute

sortOrder = navtree_properties.getProperty('sortOrder', None)
if sortOrder is not None:
query['sort_order'] = sortOrder

if navtree_properties.getProperty('enable_wf_state_filtering', False):
query['review_state'] = navtree_properties.getProperty('wf_states_to_show', [])

query['is_default_page'] = False

if site_properties.getProperty('disable_nonfolderish_sections', False):
query['is_folderish'] = True

# Get ids not to list and make a dict to make the search fast
idsNotToList = navtree_properties.getProperty('idsNotToList', ())
excludedIds = {}
for id in idsNotToList:
excludedIds[id]=1

rawresult = portal_catalog.searchResults(**query)

# now add the content to results
for item in rawresult:
if not (excludedIds.has_key(item.getId) or item.exclude_from_nav):
id, item_url = get_view_url(item)
data = {'name' : utils.pretty_title_or_id(context, item),
'id' : item.getId,
'url' : item_url,
'description': item.Description}
result.append(data)
return result


* configure.zcml:

<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:five="http://namespaces.zope.org/five"
xmlns:browser="http://namespaces.zope.org/browser">

<browser:viewlet
name="plone.global_sections"
manager="plone.app.layout.viewlets.interfaces.IPortalHeader"
class=".common.GlobalSectionsViewlet"
permission="zope2.View"
layer="inigo.theme.browser.interfaces.IThemeSpecific"
/>

</configure>


* sections.pt:


<tal:tabs tal:condition="view/portal_tabs"
i18n:domain="plone">
<h5 class="hiddenStructure" i18n:translate="heading_sections">Sections</h5>

<ul id="portal-globalnav">
<tal:tabs tal:repeat="tab view/portal_tabs"><li tal:attributes="id string:portaltab-${tab/id};
class python:view.selected_portal_tab==tab['id'] and 'selected' or 'plain'"
><a href=""
tal:content="tab/name"
tal:attributes="href tab/url;
title tab/description|nothing">
Tab Name
</a>
<tal:block omit-tag=""
tal:define="subnav tab/subtab;">
<tal:block omit-tag="" tal:condition="subnav">
<ul class="nn-twolevel-subnav">
<tal:tabs tal:repeat="subtab subnav">
<li tal:attributes="id string:portaltab-${subtab/id};">
<a href="" class="" tal:attributes="href subtab/url;" accesskey="accesskeys-tabs" i18n:attributes="accesskey">
<tal:block omit-tag="" i18n:translate="" >
<span tal:replace="subtab/name">Tab Name</span>
</tal:block>
</a>
</li>
</tal:tabs>
</ul>
</tal:block>
</tal:block>
</li></tal:tabs>
</ul>
</tal:tabs>


5. Once the viewlet folder is complete, you need to add it to your theme product configure.zcml by adding:


<include package=".viewlet" />


6. Then you should modify your theme main css file (usually public.css.dtml) so that it would hide the submenu and reveal it only on hover of the main tab:


#portal-globalnav {
position:relative;
display: inline;
}

#portal-globalnav li ul {
display: none;
visibility: hidden;
position: absolute;
z-index: 200;
}

#portal-globalnav li ul li {
display: block;
margin: 0;
padding: 0;
width: 100%;
clear: left;
}

#portal-globalnav li ul li a {
display: block;
}

#portal-globalnav li:hover ul {
visibility: visible;
display: block;
}

#portal-globalnav li {
display: inline;
position: relative;
float: left;
}


Additional Information

The code for the getsubtab function was mostly copied from the CMFPlone/browser/navigation.py topLevelTabs function. This is so that the same behaviour can be expected for our sub menu as our normal tabs (eg. hide from navigation etc). The CSS given above is mostly just to hide and show the sub-menu. It would require additional mark-up to make it compeletely compatible and completely blend with your theme.