Commits

seccanj committed f5dd6bc

Release 1.4.7: Enhancement #8907 and #8908, fixed bug 8869. Added Spanish and German.
Release 1.4.7 (2011-08-28):
o Enhancement #8907 (Track-Hacks): Add template for "New TestCase" - Thanks a lot to Christian for the hard work on this enhancement!!!
Now you can define templates for your new test catalogs and new test cases, and assign default templates based
on each test catalog!
o Enhancement #8908 (Track-Hacks): Possiblity to change test case status from the tree view.
No more need to open each test case in a plan to set its result, you can now do this directly from the tree view!
o Fixed Ticket #8869 (Track-Hacks): Loading of Test Manager takes too long and sometimes time out
o Added Spanish and German catalogs! Thanks a lot to Christian and Andreas for the translations!!! Italian was already part of the plugin.

Comments (0)

Files changed (120)

BUILD.txt

File contents unchanged.

INSTALLATION.txt

File contents unchanged.

LICENSE.txt

File contents unchanged.
 
 (Refer to the tickets on trac-hacks or SourceForge for complete descriptions.)
 
+Release 1.4.7 (2011-08-28):
+  o Enhancement #8907 (Track-Hacks): Add template for "New TestCase" - Thanks a lot to Christian for the hard work on this enhancement!!!
+                                     Now you can define templates for your new test catalogs and new test cases, and assign default templates based
+                                     on each test catalog!
+  o Enhancement #8908 (Track-Hacks): Possiblity to change test case status from the tree view.
+                                     No more need to open each test case in a plan to set its result, you can now do this directly from the tree view!
+  o Fixed Ticket #8869 (Track-Hacks): Loading of Test Manager takes too long and sometimes time out
+  o Added Spanish and German catalogs! Thanks a lot to Christian and Andreas for the translations!!! Italian was already part of the plugin.
+
 Release 1.4.6 (2011-06-19):
   o Fixed Ticket #8871 (Track-Hacks): No # allowed at custom fields
   o Fixed Ticket #8873 (Track-Hacks): css styles ar not compatible with the agilo plugin
 rem python setup.py update_catalog_js -l it
 rem python ./setup.py compile_catalog -f -l it
 rem python ./setup.py compile_catalog_js -f -l it
+rem python setup.py update_catalog -l es
+rem python setup.py update_catalog_js -l es
+rem python ./setup.py compile_catalog -f -l es
+rem python ./setup.py compile_catalog_js -f -l es
+rem python setup.py update_catalog -l de
+rem python setup.py update_catalog_js -l de
+rem python ./setup.py compile_catalog -f -l de
+rem python ./setup.py compile_catalog_js -f -l de
 
 python setup.py bdist_egg
 xcopy /y dist\*.egg ..\..\bin
 #python ./setup.py update_catalog_js -l it
 #python ./setup.py compile_catalog -f -l it
 #python ./setup.py compile_catalog_js -f -l it
+#python ./setup.py update_catalog -l es
+#python ./setup.py update_catalog_js -l es
+#python ./setup.py compile_catalog -f -l es
+#python ./setup.py compile_catalog_js -f -l es
+#python ./setup.py update_catalog -l de
+#python ./setup.py update_catalog_js -l de
+#python ./setup.py compile_catalog -f -l de
+#python ./setup.py compile_catalog_js -f -l de
 
 python setup.py bdist_egg
 cp dist/*.egg ../../bin

build_wininst.cmd

File contents unchanged.

clean.cmd

File contents unchanged.

clean.sh

File contents unchanged.

package.cmd

File contents unchanged.

package.sh

File contents unchanged.

sqlexecutor/trunk/setup.py

File contents unchanged.

sqlexecutor/trunk/sqlexecutor/LICENSE.txt

File contents unchanged.

sqlexecutor/trunk/sqlexecutor/README.txt

File contents unchanged.

sqlexecutor/trunk/sqlexecutor/__init__.py

File contents unchanged.

sqlexecutor/trunk/sqlexecutor/htdocs/place.holder

File contents unchanged.

sqlexecutor/trunk/sqlexecutor/sql.py

File contents unchanged.

sqlexecutor/trunk/sqlexecutor/templates/empty.html

File contents unchanged.

sqlexecutor/trunk/sqlexecutor/templates/result.html

File contents unchanged.

testman4trac/trunk/messages-js.cfg

File contents unchanged.

testman4trac/trunk/setup.cfg

File contents unchanged.

testman4trac/trunk/setup.py

 
 setup(
     name='TestManager',
-    version='1.4.6',
+    version='1.4.7',
     packages=['testmanager'],
     package_data={
         'testmanager' : [

testman4trac/trunk/testmanager/INSTALLATION.txt

File contents unchanged.

testman4trac/trunk/testmanager/LICENSE.txt

File contents unchanged.

testman4trac/trunk/testmanager/README.txt

 
 (Refer to the tickets on trac-hacks or SourceForge for complete descriptions.)
 
+Release 1.4.7 (2011-08-28):
+  o Enhancement #8907 (Track-Hacks): Add template for "New TestCase" - Thanks a lot to Christian for the hard work on this enhancement!!!
+                                     Now you can define templates for your new test catalogs and new test cases, and assign default templates based
+                                     on each test catalog!
+  o Enhancement #8908 (Track-Hacks): Possiblity to change test case status from the tree view.
+                                     No more need to open each test case in a plan to set its result, you can now do this directly from the tree view!
+  o Fixed Ticket #8869 (Track-Hacks): Loading of Test Manager takes too long and sometimes time out
+  o Added Spanish and German catalogs! Thanks a lot to Christian and Andreas for the translations!!! Italian was already part of the plugin.
+
 Release 1.4.6 (2011-06-19):
   o Fixed Ticket #8871 (Track-Hacks): No # allowed at custom fields
   o Fixed Ticket #8873 (Track-Hacks): css styles ar not compatible with the agilo plugin

testman4trac/trunk/testmanager/__init__.py

 import stats
 import workflow
 import rpcsupport
+import admin

testman4trac/trunk/testmanager/admin.py

+"""
+ Created by Christian Masopust 2011
+ Copyright (c) 2011 Christian Masopust. All rights reserved.
+"""
+
+import re
+import os.path
+from operator import itemgetter
+
+from trac.core import *
+from trac.db import *
+from trac.web.chrome import add_notice, add_warning, add_stylesheet
+from trac.admin.web_ui import IAdminPanelProvider
+from trac.wiki.formatter import format_to_html
+from trac.mimeview.api import Context
+
+from testmanager.api import *
+from tracgenericclass.util import *
+from testmanager.util import *
+
+try:
+    from testmanager.api import _, tag_, N_
+except ImportError:
+	from trac.util.translation import _, N_
+	tag_ = _
+
+class TestManagerAdmin(Component):
+    """
+    Provide the functionality to add, edit and create
+    templates for TestCases and TestCatalogs
+    """
+
+    implements(IAdminPanelProvider)
+
+    # IAdminPanelProvider methods:
+    #
+    def get_admin_panels(self, req):
+        if req.perm.has_permission('TRAC_ADMIN'):
+            yield('testmanager', 'Test Manager', 'settings', _("Settings"))
+            yield('testmanager', 'Test Manager', 'templates', _("Templates"))
+
+    def render_admin_panel(self, req, cat, page, component):
+        if page == 'settings':
+            return self._render_settings(req, cat, page, component)
+        if page == 'templates':
+            return self._render_templates(req, cat, page, component)
+
+
+    def _render_settings(self, req, cat, page, component):
+        req.perm.assert_permission('TRAC_ADMIN')
+
+        data = {}
+
+        try:
+            if req.method == 'POST':
+                default_days_back = req.args.get('default_days_back')
+                default_interval = req.args.get('default_interval')
+                yui_base_url = req.args.get('yui_base_url')
+
+                self.env.config.set('testmanager', 'default_days_back', default_days_back)
+                self.env.config.set('testmanager', 'default_interval', default_interval)
+                self.env.config.set('testmanager', 'yui_base_url', yui_base_url)
+                self.env.config.save()
+                add_notice(req, _("Settings saved"))
+        except:
+            self.env.log.error(formatExceptionInfo())
+            add_warning(req, _("Error saving the settings"))
+
+        data['default_days_back'] = self.env.config.get('testmanager', 'default_days_back')
+        data['default_interval'] = self.env.config.get('testmanager', 'default_interval')
+        data['yui_base_url'] = self.env.config.get('testmanager', 'yui_base_url')
+
+        return 'admin_settings.html', data
+
+    def _render_templates(self, req, cat, page, component):
+        req.perm.assert_permission('TRAC_ADMIN')
+
+        for key, value in req.args.items():
+            self.env.log.debug("Key: %s, Value: %s", key, value)
+
+        testmanagersystem = TestManagerSystem(self.env)
+
+        context = Context.from_request(req)
+
+        data = {}
+
+        data['template_overview'] = True
+        data['edit_template'] = False
+
+        data['tc_templates'] = testmanagersystem.get_templates(testmanagersystem.TEMPLATE_TYPE_TESTCASE)
+        data['tcat_templates'] = testmanagersystem.get_templates(testmanagersystem.TEMPLATE_TYPE_TESTCATALOG)
+        data['tcat_list'] = testmanagersystem.get_testcatalogs()
+        data['tcat_selected'] = testmanagersystem.get_default_tcat_template_id()
+
+        if req.method == 'POST':
+            
+            # add a Test Case template?
+            if req.args.get('tc_add'):
+                tc_name = req.args.get('tc_add_name')
+                self.env.log.debug("Add new TC-template: %s" % tc_name)
+
+                if len(tc_name) > 0:
+                    if testmanagersystem.template_exists(tc_name, testmanagersystem.TEMPLATE_TYPE_TESTCASE):
+                        data['tc_add_name'] = tc_name
+                        add_warning(req, _("A Test Case template with that name already exists"))
+                    else:
+                        data['template_overview'] = False
+                        data['edit_template'] = True
+                        data['t_edit_type'] = testmanagersystem.TEMPLATE_TYPE_TESTCASE
+                        data['t_edit_name'] = tc_name
+                        data['t_edit_action'] = 'ADD'
+                else:
+                    add_warning(req, _("Please enter a Template name first"))
+
+            # add a Test Catalog template?
+            if req.args.get('tcat_add'):
+                tcat_name = req.args.get('tcat_add_name')
+                self.env.log.debug("Add new TCat-template: %s" % tcat_name)
+
+                if len(tcat_name) > 0:
+                    if testmanagersystem.template_exists(tcat_name, testmanagersystem.TEMPLATE_TYPE_TESTCATALOG):
+                        data['tcat_add_name'] = tcat_name
+                        add_warning(req, _("A Test Catalog template with that name already exists"))
+                    else:
+                        data['template_overview'] = False
+                        data['edit_template'] = True
+                        data['t_edit_type'] = testmanagersystem.TEMPLATE_TYPE_TESTCATALOG
+                        data['t_edit_name'] = tcat_name
+                        data['t_edit_action'] = 'ADD'
+                else:
+                    add_warning(req, _("Please enter a Template name first"))
+
+            # delete a Test Case template?
+            if req.args.get('tc_del'):
+                tc_sel = req.args.get('tc_sel')
+                for t_id in tc_sel:
+                    t = testmanagersystem.get_template_by_id(t_id)
+                    if testmanagersystem.template_in_use(t_id):
+                        add_warning(req, _("Template '%s' not removed as it is in use for a Test Catalog") % t['name'])
+                        continue
+                    
+                    self.env.log.debug("remove test case template with id: " + t_id)
+                    if not testmanagersystem.remove_template(t_id):
+                        add_warning(req, _("Error deleting Test Case template '%s'") % t['name'])
+                    else:
+                        add_notice(req, _("Test Case template '%s' deleted") % t['name'])
+                    
+                data['tc_templates'] = testmanagersystem.get_templates(testmanagersystem.TEMPLATE_TYPE_TESTCASE)
+                data['tcat_templates'] = testmanagersystem.get_templates(testmanagersystem.TEMPLATE_TYPE_TESTCATALOG)
+
+            # delete a Test Catalog template?
+            if req.args.get('tcat_del'):
+                tcat_sel = req.args.get('tcat_sel')
+                tcat_default = testmanagersystem.get_default_tcat_template_id()
+                for t_id in tcat_sel:
+                    t = testmanagersystem.get_template_by_id(t_id)
+                    if t_id == tcat_default:
+                        add_warning(req, _("Template '%s' not removed as it is currently the default template") % t['name'])
+                        continue
+                    
+                    self.env.log.debug("remove test catalog template with id: " + t_id)
+                    if not testmanagersystem.remove_template(t_id):
+                        add_warning(req, _("Error deleting Test Catalog template '%s'") % t['name'])
+                    else:
+                        add_notice(req, _("Test Catalog template '%s' deleted") % t['name'])
+                        
+                data['tc_templates'] = testmanagersystem.get_templates(testmanagersystem.TEMPLATE_TYPE_TESTCASE)
+                data['tcat_templates'] = testmanagersystem.get_templates(testmanagersystem.TEMPLATE_TYPE_TESTCATALOG)
+
+            # save default Test Catalog template
+            if req.args.get('tcat_default_save'):
+                tcat_default = req.args.get('tcat_default')
+                if testmanagersystem.set_config_property('TEST_CATALOG_DEFAULT_TEMPLATE', tcat_default):
+                    add_notice(req, _("Default Test Catalog template updated"))
+                    data['tcat_selected'] = tcat_default
+                else:
+                    add_warning(req, _("Failed to update default Test Catalog template"))
+
+            # save templates for TestCatalogs
+            if req.args.get('tc_templates_save'):
+                warning = False
+                for key, value in req.args.items():
+                    self.env.log.debug("checking key: " + key)
+                    if 'TC_TEMPLATE_FOR_TCAT_' in key:
+                        self.env.log.debug("saving tc-template for: %s, value: %s" % (key, value))
+                        if not testmanagersystem.set_config_property(key, value):
+                            warning = True
+                if warning:
+                    add_warning(req, _("Failed to update Test Case templates"))
+                else:
+                    add_notice(req, _("Default Test Case templates updated"))
+                    data['tcat_list'] = testmanagersystem.get_testcatalogs()
+
+            # preview template
+            if req.args.get('t_edit_preview'):
+                data['template_overview'] = False
+                data['edit_template'] = True
+                data['t_edit_id'] = req.args.get('t_edit_id')
+                data['t_edit_type'] = req.args.get('t_edit_type')
+                data['t_edit_name'] = req.args.get('t_edit_name')
+                data['t_edit_description'] = req.args.get('t_edit_description')
+                data['t_edit_content'] = req.args.get('t_edit_content')
+                data['t_edit_action'] = req.args.get('t_edit_action')
+                data['t_show_preview'] = True
+                data['t_preview_content'] = format_to_html(self.env, context, req.args.get('t_edit_content'))
+
+            # save an edited template?
+            if req.args.get('t_edit_save'):
+                t_id = req.args.get('t_edit_id')
+                t_type = req.args.get('t_edit_type')
+                t_name = req.args.get('t_edit_name')
+                t_desc = req.args.get('t_edit_description')
+                t_cont = req.args.get('t_edit_content')
+                t_action = req.args.get('t_edit_action')
+
+                testmanagersystem.save_template(t_id, t_name, t_type, t_desc, t_cont, t_action)
+
+                data['template_overview'] = True
+                data['edit_template'] = False
+                data['tc_templates'] = testmanagersystem.get_templates(testmanagersystem.TEMPLATE_TYPE_TESTCASE)
+                data['tcat_templates'] = testmanagersystem.get_templates(testmanagersystem.TEMPLATE_TYPE_TESTCATALOG)
+                add_notice(req, _("Template saved"))
+
+        else:
+            # method 'GET' (template selected for 'edit')
+            if component:
+                t_type = req.args.get('t_type')
+                t_id = component
+                self.env.log.debug("component: " + component)
+                template = testmanagersystem.get_template_by_id(t_id)
+
+                data['t_edit_id'] = template['id']
+                data['t_edit_type'] = template['type']
+                data['t_edit_name'] = template['name']
+                data['t_edit_description'] = template['description']
+                data['t_edit_content'] = template['content']
+                data['t_edit_action'] = 'EDIT'
+
+                data['template_overview'] = False
+                data['edit_template'] = True
+
+        add_stylesheet(req, 'common/css/wiki.css')
+        add_stylesheet(req, 'testmanager/css/admin.css')
+        return 'admin_templates.html', data

testman4trac/trunk/testmanager/api.py

 import traceback
 
 from datetime import datetime
+from operator import itemgetter
+
 from trac.core import *
 from trac.perm import IPermissionRequestor, PermissionError
 from trac.resource import Resource, IResourceManager, render_resource_link, get_resource_url
 from trac.util import get_reporter_id
 from trac.util.datefmt import utc
 from trac.web.api import IRequestHandler
+from trac.wiki.model import WikiPage
 
 from tracgenericclass.model import GenericClassModelProvider
 from tracgenericclass.util import *
 
 from testmanager.model import TestCatalog, TestCase, TestCaseInPlan, TestPlan
+from testmanager.util import *
 
 try:
     from trac.util.translation import domain_functions
         'testcase': 'NEXT_TESTCASE_ID',
         'testplan': 'NEXT_PLAN_ID'
     }
+    
+    TEMPLATE_TYPE_TESTCASE = 'TC'
+    TEMPLATE_TYPE_TESTCATALOG = 'TCAT'
 
     outcomes_by_color = {}
     outcomes_by_name = {}
                 self.outcomes_by_name[outcome] = [color, self.outcomes_by_color[color][outcome]]
 
     def get_next_id(self, type):
-        propname = NEXT_PROPERTY_NAME[type]
+        propname = self.NEXT_PROPERTY_NAME[type]
     
+        # Get current latest ID for the desired object type
+        latest_id = self.get_config_property(propname)
+        if not latest_id:
+            latest_id = '0'
+
+        # Increment next ID
+        self.set_config_property(propname, str(int(latest_id)+1))
+
+        return latest_id
+    
+    def set_next_id(self, type_, value):
+        propname = self.NEXT_PROPERTY_NAME[type_]
+        self.set_config_property(type_, value)
+
+    def get_config_property(self, propname):
         try:
-            # Get next ID
-            db, handle_ta = get_db_for_write(self.env)
+            db = get_db(self.env)
             cursor = db.cursor()
-            sql = "SELECT value FROM testconfig WHERE propname='"+propname+"'"
+            sql = "SELECT value FROM testconfig WHERE propname=%s"
             
-            cursor.execute(sql)
+            cursor.execute(sql, (propname,))
             row = cursor.fetchone()
             
-            id = int(row[0])
-
-            # Increment next ID
+            if not row or len(row) == 0:
+                return None
+                
+            return row[0]
+            
+        except:
+            self.env.log.error("Error getting configuration property '%s'" % propname)
+            self.env.log.error(formatExceptionInfo())
+            
+            return None
+    
+    def set_config_property(self, propname, value):
+        db, handle_ta = get_db_for_write(self.env)
+        try:
             cursor = db.cursor()
-            cursor.execute("UPDATE testconfig SET value='" + str(id+1) + "' WHERE propname='"+propname+"'")
-            
+            sql = "SELECT COUNT(*) FROM testconfig WHERE propname = %s"
+            cursor.execute(sql, (propname,))
+            row = cursor.fetchone()
+            if row is not None and int(row[0]) > 0:
+                cursor.execute("""
+                               UPDATE testconfig
+                                   SET value = %s
+                                   WHERE propname = %s 
+                               """, (str(value), propname))
+            else:
+                cursor.execute("""
+                               INSERT INTO testconfig (propname,value)
+                                   VALUES (%s,%s)
+                               """, (propname, str(value)))
             if handle_ta:
                 db.commit()
+ 
+            return True
+ 
         except:
+            self.env.log.error("Error setting configuration property '%s' to '%s'" % (propname, str(value)))
             self.env.log.error(formatExceptionInfo())
             db.rollback()
-            raise
 
-        return str(id)
-    
-    def set_next_id(self, type, value):
-        propname = NEXT_PROPERTY_NAME[type]
-        
-        try:
-            # Set next ID to the input value
-            db, handle_ta = get_db_for_write(self.env)
-            cursor = db.cursor()
-            cursor.execute("UPDATE testconfig SET value='" + str(value) + "' WHERE propname='"+propname+"'")
-           
-            if handle_ta:
-                db.commit()
-        except:
-            self.env.log.error(formatExceptionInfo())
-            db.rollback()
-            raise
+        return False
     
     def get_default_tc_status(self):
         """Returns the default test case in plan status"""
                     tcip.set_status(status, author)
                     tcip.save_changes(author, "Status changed")
                 else:
-                    tcip['page_name'] = path
+                    tc = TestCase(self.env, id)
+                    tcip['page_name'] = tc['page_name']
                     tcip.set_status(status, author)
                     tcip.insert()
                 
                 pagename += '_TT'+str(id)
 
                 try:
-                    new_tc = TestCatalog(self.env, id, pagename, title, '')
+                    # Add template if exists...
+                    new_content = self.get_default_tcat_template()
+                    new_tc = TestCatalog(self.env, id, pagename, title, new_content)
                     new_tc.author = author
                     new_tc.remote_addr = req.remote_addr
                     # This also creates the Wiki page
                 except:
                     self.env.log.error("Error adding test catalog!")
                     self.env.log.error(formatExceptionInfo())
+                    add_notice(req, _("Error adding test catalog"))
                     req.redirect(req.href.wiki(path))
 
                 # Redirect to see the new wiki page.
                 else:
                     # Normal creation of a new test case
                     try:
-                        new_tc = TestCase(self.env, id, pagename, title, '')
+                        # Add template if it exists
+                        new_content = self.get_tc_template(path)
+                        new_tc = TestCase(self.env, id, pagename, title, new_content)
                         new_tc.author = author
                         new_tc.remote_addr = req.remote_addr
                         # This also creates the Wiki page
                     except:
                         self.env.log.error("Error adding test case!")
                         self.env.log.error(formatExceptionInfo())
+                        add_notice(req, _("Error adding test case"))
                         req.redirect(req.path_info)
 
                     # Redirect to edit the test case description
                 gcm_provider.custom_fields('testcase', True)
                 gcm_provider.fields(True)
                 
+                
+    # Test case import management
+                
     def _process_imported_testcase_row(self, row_num, row, cat_name, author, remote_addr, testcaseimport_info):
         if len(row) < 2:
             testcaseimport_info['errors'].append([row_num, '', 'At least two columns are required.'])
             self.env.log.error("Error importing test case number %s:\n%s" % (row_num, row))
             self.env.log.error(formatExceptionInfo())
 
+
+    # Template management
+
+    def get_default_tcat_template_id(self):
+        """ get default TestCatalog template id """
+        try:
+            return self.get_config_property('TEST_CATALOG_DEFAULT_TEMPLATE')
+
+        except:
+            self.env.log.error("Error getting default test catalog template id")
+            self.env.log.error(formatExceptionInfo())
+            return None
+
+    def get_default_tcat_template(self):
+        """ get default TestCatalog template """
+        try:
+            # first get template id from testconfig
+            t_id = self.get_config_property('TEST_CATALOG_DEFAULT_TEMPLATE')
+            if not t_id:
+                return ''
+
+            # now get template
+            result = self.get_template_by_id(t_id)
+            if not result:
+                return ''
+                
+            return result['content']
+
+        except:
+            self.env.log.error("Error getting default test catalog template")
+            self.env.log.error(formatExceptionInfo())
+            return None
+
+    def get_tc_template_id_for_catalog(self, t_cat_id):
+        """ get test case template for catalog with specified id """
+        try:
+            return self.get_config_property('TC_TEMPLATE_FOR_TCAT_' + t_cat_id)
+
+        except:
+            self.env.log.error("Error getting default test catalog template id")
+            self.env.log.error(formatExceptionInfo())
+            return None
+
+    def get_tc_template(self, t_cat_page):
+        """ get TestCase template for TestCatalog """
+        db = get_db(self.env)
+        cursor = db.cursor()
+
+        try:
+            # first get TestCatalog ID
+            t_cat_id = t_cat_page.rpartition('TT')[2]
+
+            # now get Template ID
+            t_id = self.get_tc_template_id_for_catalog(t_cat_id)
+            if not t_id:
+                return ''
+
+            # and finally get the template
+            result = self.get_template_by_id(t_id)
+            if not result:
+                return ''
+                
+            return result['content']
+
+        except:
+            self.env.log.error("Error getting test case template for catalog %s" % t_cat_page)
+            self.env.log.error(formatExceptionInfo())
+            return None
+
+    def get_template_by_id(self, t_id):
+        """ Returns a template text by its id """
+        db = get_db(self.env)
+        cursor = db.cursor()
+
+        try:
+            sql = "SELECT id, name, type, description, content FROM testmanager_templates WHERE id = %s"
+            cursor.execute(sql, (t_id,))
+            result = None
+            for id_, name, type_, description, content in cursor:
+                result = { 'id': id_, 'name': name, 'type': type_, 'description': description, 'content': content }
+                self.env.log.debug(result)
+            return result
+
+        except:
+            self.env.log.error("Error getting template with id %s" % t_id)
+            self.env.log.error(formatExceptionInfo())
+            return None
+
+    def get_template_by_name(self, t_name, t_type):
+        """ Get a single template by name and type """
+        db = get_db(self.env)
+        cursor = db.cursor()
+        
+        try:
+            sql = "SELECT id, name, type, description, content FROM testmanager_templates WHERE name = %s AND type = %s;"
+            cursor.execute(sql, (t_name, t_type))
+            result = None
+            for id_, name, type_, description, content in cursor:
+                result = { 'id': id_, 'name': name, 'type': type_, 'description': description, 'content': content }
+            return result
+
+        except:
+            self.env.log.error("Error getting template with name '%s' and type '%s'" % (t_name, t_type))
+            self.env.log.error(formatExceptionInfo())
+            return None
+
+    # save a template
+    def save_template(self, t_id, t_name, t_type, t_desc, t_cont, t_action):
+        db, handle_ta = get_db_for_write(self.env)
+        cursor = db.cursor()
+
+        try:
+            if t_action == 'ADD':
+                t_id = self.get_next_template_id()
+                self.env.log.debug("next id is: " + t_id)
+                cursor.execute("""
+                    INSERT INTO testmanager_templates (id, name, type, description, content) 
+                        VALUES (%s,%s,%s,%s,%s)
+                """, (t_id, t_name, t_type, t_desc, t_cont))
+            else:
+                cursor.execute("""
+                    UPDATE testmanager_templates 
+                        SET description = %s, content = %s 
+                        WHERE id = %s AND name = %s AND type = %s
+                """, (t_desc, t_cont, t_id, t_name, t_type))
+
+            if handle_ta:
+                db.commit()
+                
+        except:
+            self.env.log.error("Error saving template with id '%s'" % t_id)
+            self.env.log.error(formatExceptionInfo())
+            db.rollback()
+            return False
+            
+        return True
+
+    def remove_template(self, t_id):
+        """ Removes a single template by id """
+        db, handle_ta = get_db_for_write(self.env)
+        cursor = db.cursor()
+        
+        try:
+            sql = "DELETE FROM testmanager_templates WHERE id = %s"
+            self.env.log.debug("removing template with id '%s'" % t_id)
+            cursor.execute(sql, (t_id,))
+            
+            if handle_ta:
+                db.commit()
+
+        except:
+            self.env.log.error("Error removing template with id '%s'" % t_id)
+            self.env.log.error(formatExceptionInfo())
+            db.rollback()
+            return False
+        
+        return True
+
+    def get_templates(self, t_type):
+        """ Get all templates of desired type """
+        db = get_db(self.env)
+        cursor = db.cursor()
+
+        items = []
+        
+        try:
+            sql = "SELECT id, name, type, description, content FROM testmanager_templates WHERE type = %s ORDER BY name" 
+            cursor.execute(sql, (t_type,))
+            for id_, name, type_, description, content in cursor:
+                template = { 'id': id_, 'name': name, 'type': type_, 'description': description, 'content': content }
+                items.append(template)
+            
+        except:
+            self.env.log.error("Error retrieving all the templates of type '%s'" % t_type)
+            self.env.log.error(formatExceptionInfo())
+
+        return items
+
+    def template_exists(self, name, t_type):
+        """ Check if a given template with desired name and type already exists """
+        db = get_db(self.env)
+        cursor = db.cursor()
+        
+        try:
+            sql = "SELECT COUNT(id) FROM testmanager_templates WHERE name = %s AND type = %s"
+            cursor.execute(sql, (name, t_type))
+            row = cursor.fetchone()
+
+            if row is not None and int(row[0]) > 0:
+                return True
+
+        except:
+            self.env.log.error("Error checking if template with name '%s' and type '%s' exists" % (name, t_type))
+            self.env.log.error(formatExceptionInfo())
+
+        return False
+
+    def template_in_use(self, t_id):
+        """ Check if a given Test Case template is in use """
+        db = get_db(self.env)
+        cursor = db.cursor()
+        
+        try:
+            sql = "SELECT COUNT(*) FROM testconfig where value = %s AND propname LIKE 'TC_TEMPLATE_FOR_TCAT_%%';"
+            cursor.execute(sql, (t_id))
+            row = cursor.fetchone()
+            
+            if int(row[0]) > 0:
+                return True
+            else:
+                return False
+        except:
+            self.env.log.error("Error checking if template with id '%s' is in use" % (t_id))
+            self.env.log.error(formatExceptionInfo())
+        
+        # return true, just to be save and not remove a template in case of other errors
+        return True
+
+    def get_next_template_id(self):
+        """ Get next id to assign a new temmplate """
+        db = get_db(self.env)
+        cursor = db.cursor()
+        ids = []
+        try:
+            sql = "SELECT id FROM testmanager_templates;"
+            cursor.execute(sql)
+            for row in cursor:
+                ids.append(int(row[0]))
+            if ids:
+                ids.sort()
+                return (str(ids.pop() + 1))
+            else:
+                return '0'
+        except:
+            self.env.log.error("Error retrieving all the templates of type '%s'" % t_type)
+            self.env.log.error(formatExceptionInfo())
+            raise
+
+    def get_testcatalogs(self):
+        """ get list of testcatalogs """
+        
+        # TODO: Use the TestCatalog class instead
+        
+        db = get_db(self.env)
+        cursor = db.cursor()
+        cursor.execute("SELECT * from testcatalog")
+        items = []
+        for row in cursor:
+            c_id = row[0]
+            c_name = row[1]
+            wikipage = WikiPage(self.env, c_name)
+            c_title = get_page_title(wikipage.text)
+            c_template = self.get_tc_template_id_for_catalog(c_id)
+            cat = {'id': c_id, 'name': c_name, 'title': c_title, 'template': c_template}
+            items.append(cat)
+            
+        return sorted(items, key=itemgetter('title'))
+

testman4trac/trunk/testmanager/htdocs/css/admin.css

+
+/* Table Listing */
+.listing,
+#legenda {
+    /* border: 1px solid #999; */
+    border: 1px solid #d7d7d7;
+    border-spacing: 0;
+    background-color: #fff;
+    padding: 0;
+}
+
+.listing {
+  width: 100%;
+}
+
+#dirlist a { display: inline;}
+
+.listing caption {
+    font-weight: bold;
+    text-align: left;
+}
+.listing tr {
+    text-shadow: 0 0 0 #fff;
+}
+.listing td,
+.listing th {
+    border-bottom: 1px solid #ddd;
+    vertical-align: top;
+    padding: 0 9px;
+    line-height: 26px;
+    border-right: 1px dotted #ddd;
+    overflow: hidden;
+}
+
+.listing th {
+    border-right: 1px solid #fff;
+    background: #ddd url("../images/gradient.png") top repeat-x;
+    text-align: left;
+    color: #666;
+    font-weight: bold;
+    text-shadow: 0 1px 0 #fff;
+}
+
+.listing th a {
+        color: #666;
+}
+

testman4trac/trunk/testmanager/htdocs/css/blitzer/images/ui-bg_diagonals-thick_75_f3d8d8_40x40.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/css/blitzer/images/ui-bg_dots-small_65_a6a6a6_2x2.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/css/blitzer/images/ui-bg_flat_0_333333_40x100.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/css/blitzer/images/ui-bg_flat_65_ffffff_40x100.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/css/blitzer/images/ui-bg_flat_75_ffffff_40x100.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/css/blitzer/images/ui-bg_glass_55_fbf8ee_1x400.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/css/blitzer/images/ui-bg_highlight-hard_100_eeeeee_1x100.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/css/blitzer/images/ui-bg_highlight-hard_100_f6f6f6_1x100.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/css/blitzer/images/ui-bg_highlight-soft_15_cc0000_1x100.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/css/blitzer/images/ui-icons_004276_256x240.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/css/blitzer/images/ui-icons_cc0000_256x240.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/css/blitzer/images/ui-icons_ffffff_256x240.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/css/blitzer/jquery-ui-1.8.13.custom.css

File contents unchanged.

testman4trac/trunk/testmanager/htdocs/css/images/nav-bg.gif

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/css/images/nav-bg.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/css/images/nav_dropdown_grad.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/css/images/nav_dropdown_sep.gif

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/css/images/nav_separator.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/css/images/submenu-bottom.gif

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/css/images/submenu-bottom.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/css/images/submenu-selected-bottom.gif

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/css/images/submenu-selected-top.gif

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/css/menu.css

File contents unchanged.

testman4trac/trunk/testmanager/htdocs/css/testmanager.css

     margin-right: 3px;
 }
 
+.statusIconElement {
+    position: relative; 
+    top: 4px;
+    margin-right: 3px;
+}
+
 .rightIcon {
     background: transparent url(../images/pencil.png) no-repeat scroll 0 0;
     padding-right:25px;
     display: none;
 }
 
+/* New status change context menu */
+
+.statusContextMenuDiv {
+	cursor: pointer;
+	z-index: 9000;
+	position: absolute;
+}
+
+ul.statusContextMenuUl {
+}
+
+ul.statusContextMenuUl > li {
+	float:left;
+	position:relative;
+	padding: 7px;
+	background-color: white;
+}
+
+ul.statusContextMenuUl > li > img {
+	padding: 1px;
+	background-color: white;
+}
+
+.statusContextSubMenuDiv {
+	cursor: pointer;
+	z-index: 9999;
+	position: absolute;
+}
+
+ul.statusContextSubMenuUl {
+	margin: 0px;
+	font-size: x-small;
+}
+
+ul.statusContextSubMenuUl > li {
+	clear:both;
+	color: black;
+	background-color: #eeeeee;
+	font-size: small;
+	padding-left: 8px;
+	padding-right: 8px;
+    margin-left: 0px;
+}
+
+ul.statusContextSubMenuUl > li:hover {
+	clear:both;
+	color: white;
+	background-color: purple;
+}
+
+ul.statusContextMenuUl > li > ul {
+	display: none;
+}
+
+ul.statusContextMenuUl > li > ul > li {
+	clear:both;
+	display: none;
+	color: black;
+	background-color: white;
+}
+
+ul.statusContextMenuUl > li > ul > li:hover {
+	clear:both;
+	display: none;
+	color: white;
+	background-color: purple;
+}
+
 .ninja {
     color: black;
     visibility: hidden;

testman4trac/trunk/testmanager/htdocs/images/empty.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/images/gradient.png

Added
New image

testman4trac/trunk/testmanager/htdocs/images/gray.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/images/green.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/images/minus.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/images/pencil.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/images/plus.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/images/red.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/images/trash.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/images/tree.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/images/tree_table.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/images/yellow.png

Old
Old image
New
New image

testman4trac/trunk/testmanager/htdocs/js/compatibility.js

File contents unchanged.

testman4trac/trunk/testmanager/htdocs/js/cookies.js

File contents unchanged.

testman4trac/trunk/testmanager/htdocs/js/de.js

+// Generated messages javascript file from compiled MO file
+babel.Translations.load({"domain":"testmanager-js","locale":"de","messages":{"Are you sure you want to delete the test plan and the state of all its contained test cases?":"Sind Sie sich sicher, da\u00df Sie diesen Testplan und den Status aller dazugeh\u00f6rigen Testf\u00e4lle l\u00f6schen m\u00f6chten?","Are you sure you want to duplicate the test catalog and all its contained test cases?":"Sind Sie sich sicher, da\u00df Sie dieses Testverzeichnis mit allen dazugeh\u00f6rigen Testf\u00e4llen kopieren m\u00f6chten?","Length between 4 and 90 characters.":"L\u00e4nge zwischen 4 und 90 Zeichen.","Results: ":"Ergebnisse:","You must specify a name. Length between 4 and 90 characters.":"Sie m\u00fcssen den Namen angeben. L\u00e4nge zwischen 4 und 90 Zeichen.","[Insert problem summary]":"[Insert problem summary]"},"plural_expr":"(n != 1)"}).install();

testman4trac/trunk/testmanager/htdocs/js/es.js

+// Generated messages javascript file from compiled MO file
+babel.Translations.load({"domain":"testmanager-js","locale":"es","messages":{"Are you sure you want to delete the test plan and the state of all its contained test cases?":"Are you sure you want to delete the test plan and the state of all its contained test cases?","Are you sure you want to duplicate the test catalog and all its contained test cases?":"\u00bfEsta seguro que desea duplicar el cat\u00e1logo y todos los casos de pruebas contenidos en \u00e9l?","Length between 4 and 90 characters.":"Longitud entre 4 y 90 caracteres.","Results: ":"Resultados:","You must specify a name. Length between 4 and 90 characters.":"Debe especificar un nombre. Longitud entre 4 y 90 caracteres.","[Insert problem summary]":"[Insert problem summary]"},"plural_expr":"(n != 1)"}).install();

testman4trac/trunk/testmanager/htdocs/js/it.js

 // Generated messages javascript file from compiled MO file
-babel.Translations.load({"domain":"testmanager-js","locale":"it","messages":{"Are you sure you want to delete the test plan and the state of all its contained test cases?":"Sei sicuro di voler eliminare il piano di test e lo stato di tutti i casi di test in esso contenuti?","Are you sure you want to duplicate the test catalog and all its contained test cases?":"Sei sicuro di voler duplicare il catalogo e tutti i casi di test in esso contenuti?","Length between 4 and 90 characters.":"Lunghezza da 4 a 90 caratteri.","Results: ":"Risultati: ","You must specify a name. Length between 4 and 90 characters.":"Devi indicare un nome. Lunghezza da 4 a 90 caratteri."},"plural_expr":"(n != 1)"}).install();
+babel.Translations.load({"domain":"testmanager-js","locale":"it","messages":{"Are you sure you want to delete the test plan and the state of all its contained test cases?":"Sei sicuro di voler eliminare il piano di test e lo stato di tutti i casi di test in esso contenuti?","Are you sure you want to duplicate the test catalog and all its contained test cases?":"Sei sicuro di voler duplicare il catalogo e tutti i casi di test in esso contenuti?","Length between 4 and 90 characters.":"Lunghezza da 4 a 90 caratteri.","Results: ":"Risultati: ","You must specify a name. Length between 4 and 90 characters.":"Devi indicare un nome. Lunghezza da 4 a 90 caratteri.","[Insert problem summary]":"[Inserire una descrizione del problema]"},"plural_expr":"(n != 1)"}).install();

testman4trac/trunk/testmanager/htdocs/js/jquery-1.5.1.min.js

File contents unchanged.

testman4trac/trunk/testmanager/htdocs/js/jquery-ui-1.8.13.custom.min.js

File contents unchanged.

testman4trac/trunk/testmanager/htdocs/js/menu.js

File contents unchanged.

testman4trac/trunk/testmanager/htdocs/js/testmanager.js

     window.location = url;
 }
 
-function creaTicket(tcName, planId, planName){ 
-	var url = baseLocation+'/newticket?testcaseid='+tcName+'&planid='+planId+'&planname='+planName+'&description=Test%20Case:%20[wiki:'+tcName+'?planid='+planId+'],%20Test%20Plan:%20'+planName+'%20('+planId+')'; 
+function creaTicket(tcName, planId, planName, summary){
+    var tokens = $('span[name=breadcrumb]').map(function() { return this.innerHTML }).get();
+    var fullSummary = "";
+    
+    for (i=1; i<tokens.length; i++) {
+        fullSummary += tokens[i] + " - ";
+    }
+    
+    fullSummary += summary + " - " + _("[Insert problem summary]");
+
+	var url = baseLocation+'/newticket?testcaseid='+tcName+'&planid='+planId+'&planname='+planName+'&summary='+stripLessSpecialChars(fullSummary)+'&description=Test%20Case:%20[wiki:'+tcName+'?planid='+planId+'],%20Test%20Plan:%20'+planName+'%20('+planId+')'; 
 	window.location = url;
 }
 
     currStatusColor = newStatusColor;
 }
 
+function changestateOnPlan(imgNodeId, tc, planid, newStatus, newStatusColor, newLabel) {
+    var url = baseLocation+"/teststatusupdate?id="+tc+"&planid="+planid+"&status="+newStatus;
+    result = doAjaxCall(url, "GET", "");
+    
+    // TODO: Handle errors in the Ajax call
+    
+    $('#'+imgNodeId)[0].src = "../chrome/testmanager/images/"+newStatusColor+".png";
+    $('#'+imgNodeId)[0].title = newLabel;
+}
+
+function showColorOutcomes(imgNodeId, color) {
+    var menuColorIcon = $("#statusContextMenuColorIcon"+color);
+    var position = menuColorIcon.offset();
+    
+    for (c in statuses_by_color) {
+        if (c == color) {
+            if (statuses_by_color[c].length > 1) {
+                $("#statusChangeSubMenu"+c)[0].innerHTML = getStatusSubContextMenuMarkup(imgNodeId, color);
+                $("#statusChangeSubMenu"+c).css({display: "block", left: position.left - 27, top: position.top + 20}).stop(true,true).fadeTo(200, 1);
+            }
+        } else {
+            $("#statusChangeSubMenu"+c).hide();
+        }
+    }
+}
+
+function bindTCStatusMenus() {
+    if (statuses_by_color) {
+        (function($) {
+            $(function() {
+                var menu = document.createElement("div");
+                menu.setAttribute("id", "statusChangeMenu");
+                menu.className = "statusContextMenuDiv";
+                menu.style.display = "none";
+                document.body.appendChild(menu);
+
+                for (color in statuses_by_color) {
+                    if (statuses_by_color[color].length > 1) {
+                        var subMenu = document.createElement("div");
+                        subMenu.setAttribute("id", "statusChangeSubMenu"+color);
+                        subMenu.className = "statusContextSubMenuDiv";
+                        subMenu.style.display = "none";
+                        document.body.appendChild(subMenu);
+                    }
+                }
+
+                $(".statusIconElement").bind('click', function(event) {
+                    event.stopPropagation();
+                
+                    var $this = $(this);
+                    var position = $this.offset();
+                    
+                    $("#statusChangeMenu")[0].innerHTML = getStatusContextMenuMarkup($this[0]);
+                    $("#statusChangeMenu").css({left: position.left - 20, top: position.top}).stop(true,true).fadeTo(200, 1);
+                });
+                
+                $(document).bind('click', function(event) {
+                    if ($("#statusChangeMenu").css("display") == "block") {
+                        $("#statusChangeMenu").hide();
+                    }
+                    
+                    for (color in statuses_by_color) {
+                        if (statuses_by_color[color].length > 1) {
+                            if ($("#statusChangeSubMenu"+color).css("display") == "block") {
+                                $("#statusChangeSubMenu"+color).hide();
+                            }
+                        }
+                    }
+                });
+            });
+        })(jQuery_testmanager);	
+    }
+}
+
+function getStatusContextMenuMarkup(imgNode) {
+    var params = imgNode.getAttribute("name").split(",");
+    var tcid = params[0];
+    var planid = params[1];
+    var path = params[2];
+    var oldStatus = params[3];
+    var oldColor = params[4];
+    var oldLabel = params[5];
+
+    var result = "<ul class=\"statusContextMenuUl\">";
+
+    for (color in statuses_by_color) {
+        if (statuses_by_color[color].length > 1) {
+            result += "<li><img id='statusContextMenuColorIcon"+color+"' class=\"statusContextMenuColorIcon\" onmouseover=\"showColorOutcomes('"+imgNode.id+"', '"+color+"');\" src=\"../chrome/testmanager/images/"+color+".png\"></img></li>";
+        } else {
+            for (outcome in statuses_by_color[color][0]) {
+                var label = statuses_by_color[color][0][outcome];
+                result += "<li><img id='statusContextMenuColorIcon"+color+"' class=\"statusContextMenuColorIcon\" onmouseover=\"showColorOutcomes('"+imgNode.id+"', '"+color+"');\" onclick=\"changestateOnPlan('"+imgNode.id+"', '"+tcid+"', '"+planid+"', '"+outcome+"', '"+color+"', '"+label+"');\" src=\"../chrome/testmanager/images/"+color+".png\"></img></li>";
+            }
+        }
+    }
+    
+    result += "</ul>";
+    
+    return result;
+}
+
+function getStatusSubContextMenuMarkup(imgNodeId, color) {
+    var imgNode = $("#"+imgNodeId)[0];
+
+    var params = imgNode.getAttribute("name").split(",");
+    var tcid = params[0];
+    var planid = params[1];
+    var path = params[2];
+    var oldStatus = params[3];
+    var oldColor = params[4];
+    var oldLabel = params[5];
+
+    var result = "<ul class='statusContextSubMenuUl'>";
+    
+    for (i=0; i<statuses_by_color[color].length; i++) {
+        for (outcome in statuses_by_color[color][i]) {
+            var label = statuses_by_color[color][i][outcome];
+            result += "<li class='statusContextSubMenuItem"+color+"' onclick=\"changestateOnPlan('"+imgNode.id+"', '"+tcid+"', '"+planid+"', '"+outcome+"', '"+color+"', '"+label+"');\">"+statuses_by_color[color][i][outcome]+"</li>";
+        }
+    }
+
+    result += "</ul>";
+
+    return result;
+}
+
+
 /******************************************************/
 /**                  Utility functions                */
 /******************************************************/
 }
 
 function stripLessSpecialChars(str) {
-    result = str.replace(/[;#&\?]/g, '');
+    result = str.replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/[;#&\?]/g, '');
     return result;
 }
 
 addLoadHandler(function() {
         checkFilter(true);
         checkMoveTCDisplays();
+        bindTCStatusMenus();
 		/* loadMessageCatalog(); */
     });

testman4trac/trunk/testmanager/locale/de/LC_MESSAGES/testmanager-js.mo

Binary file added.

testman4trac/trunk/testmanager/locale/de/LC_MESSAGES/testmanager-js.po

+# German translations for TestManager.
+# Copyright (C) 2011 Roberto Longobardi
+# This file is distributed under the same license as the TestManager
+# project.
+#
+# <andreas.podskalsky@siemens.com>, 2011.
+msgid ""
+msgstr ""
+"Project-Id-Version: Test Manager for Trac plugin\n"
+"Report-Msgid-Bugs-To: http://trac-hacks.org/wiki/TestManagerForTracPlugin"
+"\n"
+"POT-Creation-Date: 2011-08-21 22:54+0200\n"
+"PO-Revision-Date: 2011-08-18 13:49+0000\n"
+"Last-Translator: podskalsky <andreas.podskalsky@siemens.com>\n"
+"Language-Team: German "
+"(http://www.transifex.net/projects/p/testman4trac/team/de/)\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.6\n"
+
+#: testmanager/htdocs/js/testmanager.js:15
+#: testmanager/htdocs/js/testmanager.js:34
+#: testmanager/htdocs/js/testmanager.js:53
+msgid "You must specify a name. Length between 4 and 90 characters."
+msgstr "Sie müssen den Namen angeben. Länge zwischen 4 und 90 Zeichen."
+
+#: testmanager/htdocs/js/testmanager.js:20
+#: testmanager/htdocs/js/testmanager.js:39
+#: testmanager/htdocs/js/testmanager.js:58
+msgid "Length between 4 and 90 characters."
+msgstr "Länge zwischen 4 und 90 Zeichen."
+
+#: testmanager/htdocs/js/testmanager.js:85
+msgid "[Insert problem summary]"
+msgstr ""
+
+#: testmanager/htdocs/js/testmanager.js:97
+msgid ""
+"Are you sure you want to duplicate the test catalog and all its contained"
+" test cases?"
+msgstr ""
+"Sind Sie sich sicher, daß Sie dieses Testverzeichnis mit allen "
+"dazugehörigen Testfällen kopieren möchten?"
+
+#: testmanager/htdocs/js/testmanager.js:104
+msgid ""
+"Are you sure you want to delete the test plan and the state of all its "
+"contained test cases?"
+msgstr ""
+"Sind Sie sich sicher, daß Sie diesen Testplan und den Status aller "
+"dazugehörigen Testfälle löschen möchten?"
+
+#: testmanager/htdocs/js/testmanager.js:307
+#: testmanager/htdocs/js/testmanager.js:456
+msgid "Results: "
+msgstr "Ergebnisse:"
+

testman4trac/trunk/testmanager/locale/de/LC_MESSAGES/testmanager.mo

Binary file added.

testman4trac/trunk/testmanager/locale/de/LC_MESSAGES/testmanager.po

+# German translations for TestManager.
+# Copyright (C) 2011 Roberto Longobardi
+# This file is distributed under the same license as the TestManager
+# project.
+#
+# <andreas.podskalsky@siemens.com>, 2011.
+msgid ""
+msgstr ""
+"Project-Id-Version: Test Manager for Trac plugin\n"
+"Report-Msgid-Bugs-To: http://trac-hacks.org/wiki/TestManagerForTracPlugin"
+"\n"
+"POT-Creation-Date: 2011-08-21 23:30+0200\n"
+"PO-Revision-Date: 2011-08-18 13:43+0000\n"
+"Last-Translator: podskalsky <andreas.podskalsky@siemens.com>\n"
+"Language-Team: German "
+"(http://www.transifex.net/projects/p/testman4trac/team/de/)\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.6\n"
+
+#: testmanager/admin.py:39 testmanager/templates/testmanagerstats.html:141
+msgid "Settings"
+msgstr "Einstellungen"
+
+#: testmanager/admin.py:40
+msgid "Templates"
+msgstr "Schablone"
+
+#: testmanager/admin.py:64
+msgid "Settings saved"
+msgstr "Einstellungen"
+
+#: testmanager/admin.py:67
+msgid "Error saving the settings"
+msgstr ""
+
+#: testmanager/admin.py:105
+msgid "A Test Case template with that name already exists"
+msgstr ""
+
+#: testmanager/admin.py:113 testmanager/admin.py:131
+msgid "Please enter a Template name first"
+msgstr ""
+
+#: testmanager/admin.py:123
+msgid "A Test Catalog template with that name already exists"
+msgstr ""
+
+#: testmanager/admin.py:139
+#, python-format
+msgid "Template '%s' not removed as it is in use for a Test Catalog"
+msgstr ""
+
+#: testmanager/admin.py:144
+#, python-format
+msgid "Error deleting Test Case template '%s'"
+msgstr ""
+
+#: testmanager/admin.py:146
+#, python-format
+msgid "Test Case template '%s' deleted"
+msgstr ""
+
+#: testmanager/admin.py:158
+#, python-format
+msgid "Template '%s' not removed as it is currently the default template"
+msgstr ""
+
+#: testmanager/admin.py:163
+#, python-format
+msgid "Error deleting Test Catalog template '%s'"
+msgstr ""
+
+#: testmanager/admin.py:165
+#, python-format
+msgid "Test Catalog template '%s' deleted"
+msgstr ""
+
+#: testmanager/admin.py:174
+msgid "Default Test Catalog template updated"
+msgstr ""
+
+#: testmanager/admin.py:177
+msgid "Failed to update default Test Catalog template"
+msgstr ""
+
+#: testmanager/admin.py:189
+msgid "Failed to update Test Case templates"
+msgstr ""
+
+#: testmanager/admin.py:191
+msgid "Default Test Case templates updated"
+msgstr ""
+
+#: testmanager/admin.py:222
+msgid "Template saved"
+msgstr ""
+
+#: testmanager/api.py:223 testmanager/macros.py:539 testmanager/macros.py:911
+msgid "Timestamp"
+msgstr "Zeitstempel"
+
+#: testmanager/api.py:223 testmanager/macros.py:489 testmanager/macros.py:539
+#: testmanager/macros.py:911 testmanager/model.py:553
+msgid "Author"
+msgstr "Autor"
+
+#: testmanager/api.py:223 testmanager/api.py:236 testmanager/macros.py:489
+#: testmanager/macros.py:911 testmanager/model.py:546
+msgid "Status"
+msgstr "Status"
+
+#: testmanager/api.py:346
+msgid "Error adding test catalog"
+msgstr "Ergänzten Test-Verzeichnis"
+
+#: testmanager/api.py:460
+msgid "Error adding test case"
+msgstr ""
+
+#: testmanager/macros.py:218
+msgid "All Catalogs"
+msgstr "Alle Verzeichnisse"
+
+#: testmanager/macros.py:306 testmanager/macros.py:327
+#: testmanager/macros.py:444 testmanager/macros.py:466
+msgid "Filter:"
+msgstr "Filter:"
+
+#: testmanager/macros.py:306 testmanager/macros.py:327
+#: testmanager/macros.py:444 testmanager/macros.py:466
+msgid ""
+"Type the test to search for, even more than one word. You can also filter"
+" on the test case status (untested, successful, failed)."
+msgstr ""
+"Sucheingabefeld für Testfall. Auch mehrere Wörter möglich. Filterung kann"
+" auch den Testfall-Status (untested, successful, failed) beinhalten."
+
+#: testmanager/macros.py:307 testmanager/macros.py:445
+msgid "Expand all"
+msgstr "Alles ausklappen"
+
+#: testmanager/macros.py:307 testmanager/macros.py:445
+msgid "Collapse all"
+msgstr "Alles einklappen"
+
+#: testmanager/macros.py:332 testmanager/macros.py:471 testmanager/model.py:552
+#: testmanager/templates/admin_templates.html:28
+#: testmanager/templates/admin_templates.html:59
+#: testmanager/templates/admin_templates.html:134
+msgid "Name"
+msgstr "Name"
+
+#: testmanager/macros.py:341 testmanager/macros.py:480 testmanager/model.py:535
+#: testmanager/model.py:539 testmanager/model.py:543 testmanager/model.py:549
+msgid "ID"
+msgstr "ID"
+
+#: testmanager/macros.py:351 testmanager/templates/admin_templates.html:28
+#: testmanager/templates/admin_templates.html:59
+#: testmanager/templates/admin_templates.html:139
+msgid "Description"
+msgstr "Beschreibung"
+
+#: testmanager/macros.py:489
+msgid "Last Change"
+msgstr "Letzte Änderung"
+
+#: testmanager/macros.py:525
+msgid "Available Test Plans"
+msgstr "Verfügbare Testpläne"
+
+#: testmanager/macros.py:539
+msgid "Plan Name"
+msgstr "Plan-Name"
+
+#: testmanager/macros.py:545
+msgid "Open Test Plan"
+msgstr "Testplan öffnen"
+
+#: testmanager/macros.py:550
+msgid "Delete"
+msgstr "Löschen"
+
+#: testmanager/macros.py:618 testmanager/macros.py:719
+msgid "Open"
+msgstr "Öffnen"
+
+#: testmanager/macros.py:661 testmanager/macros.py:663
+msgid "Edit the Test Case"
+msgstr "Testfall bearbeiten"
+
+#: testmanager/macros.py:687 testmanager/macros.py:780
+#: testmanager/macros.py:918
+msgid "Unknown"
+msgstr "Unbekannt"
+
+#: testmanager/macros.py:860
+msgid "Change the Status:"
+msgstr "Status ändern"
+
+#: testmanager/macros.py:908
+msgid "Status change history"
+msgstr "Statusänderungen"
+
+#: testmanager/model.py:536 testmanager/model.py:540 testmanager/model.py:545
+#: testmanager/model.py:551
+msgid "Wiki page name"
+msgstr "Wiki-Seiten-Name"
+
+#: testmanager/model.py:544
+msgid "Plan ID"
+msgstr "Plan ID"
+
+#: testmanager/model.py:550
+msgid "Catalog ID"
+msgstr "Verzeichnis ID"
+
+#: testmanager/model.py:554
+msgid "Created"
+msgstr "Erstellt"
+
+#: testmanager/model.py:678 testmanager/wiki.py:339 testmanager/wiki.py:396
+msgid "Test Case"
+msgstr "Testfall"
+
+#: testmanager/model.py:682
+msgid "Test Plan"
+msgstr "Testplan"
+
+#: testmanager/model.py:687 testmanager/stats.py:221
+msgid "Successful"
+msgstr "Erfolgreich"
+
+#: testmanager/model.py:688
+msgid "Untested"
+msgstr "Ungetestet"
+
+#: testmanager/model.py:689 testmanager/stats.py:221
+msgid "Failed"
+msgstr "Fehlgeschlagen"
+
+#: testmanager/stats.py:221
+msgid "To be tested"
+msgstr "Ungetestet"
+
+#: testmanager/web_ui.py:67
+msgid "Test Manager"
+msgstr "Testmanager"
+
+#: testmanager/wiki.py:136
+msgid ""
+"Select the catalog into which to paste the Test Cases and click on 'Paste"
+" the copied Test Cases here'. "
+msgstr ""
+"Verzeichnis zum Einfügen der Testfälle auswählen und 'Kopierte Testfälle "
+"hierher einfügen' anklicken."
+
+#: testmanager/wiki.py:137 testmanager/wiki.py:141 testmanager/wiki.py:163
+#: testmanager/wiki.py:168 testmanager/wiki.py:329 testmanager/wiki.py:334
+#: testmanager/templates/admin_templates.html:155
+msgid "Cancel"