Index: quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/__init__.py
===================================================================
--- quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/__init__.py	(revision 1610)
+++ quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/__init__.py	(revision 1624)
@@ -8,5 +8,5 @@
 from Products.CMFCore.utils import getToolByName
 
-from quintagroup.seoptimizer.interfaces import IKeywords, IMappingMetaTags
+from quintagroup.seoptimizer.interfaces import IMetaKeywords, IMappingMetaTags
 from quintagroup.seoptimizer.util import SortedDict
 
@@ -54,9 +54,9 @@
 
         for key, accessor in metadata_names.items():
-            if accessor == 'seo_keywords':
-                # Set the additional matching keywords, if any
-                adapter = IKeywords(context, None)
+            if accessor == 'meta_keywords':
+                # Render all the existing keywords for the current content type
+                adapter = IMetaKeywords(context, None)
                 if adapter is not None:
-                    keywords = adapter.listKeywords()
+                    keywords = adapter.getMetaKeywords()
                     if keywords:
                         result['keywords'] = keywords
Index: quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/adapters.py
===================================================================
--- quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/adapters.py	(revision 1610)
+++ quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/adapters.py	(revision 1624)
@@ -4,44 +4,40 @@
 from Products.CMFCore.utils import getToolByName
 
-from quintagroup.seoptimizer.interfaces import IKeywords, IMappingMetaTags
+from quintagroup.seoptimizer.interfaces import IMetaKeywords, IMappingMetaTags
 from quintagroup.seoptimizer.util import SortedDict
 
 
-class AdditionalKeywords(object):
-    implements(IKeywords)
+class MetaKeywordsAdapter(object):
+    implements(IMetaKeywords)
 
     def __init__(self, context):
         self.context = context
 
-    def listKeywords(self):
+    def getMetaKeywords(self):
         """ See interface.
         """
+        request = self.context.REQUEST
+        meta_keywords = ''
+        filtered_keywords = []
         portal_props = getToolByName(self.context, 'portal_properties')
         seo_props = getToolByName(portal_props, 'seo_properties', None)
-
-        # now set type is not using because of it unordered behaviour
-        #original = set(self.context.qSEO_Keywords())
-        #additional = set(seo_props.additional_keywords)
-        #text = set(self.context.SearchableText().split())
-        #keywords = list(additional.intersection(text).union(original))
-
-        request = self.context.REQUEST
         seo_context = queryMultiAdapter((self.context, request), name='seo_context')
         if seo_context:
-            keywords = list(seo_context.seo_keywords())
-            lower_keywords = map(lambda x: x.lower(), keywords)
-            additional = seo_props.additional_keywords
+            meta_keywords = list(seo_context.meta_keywords())
+            is_test = self.context.REQUEST.get('without_metatag_keywords', None)
+            if meta_keywords and is_test is None:
+                # extract words from url page using lynx browser (test page randered without metatag keywords)
+                text = commands.getoutput('lynx --dump --nolist %s?without_metatag_keywords=1' % self.context.absolute_url()).lower()
 
-            is_test = self.context.REQUEST.get('qseo_without_additional_keywords', None)
+                # for tests package
+                if text and 'lynx: can\'t access startfile http://nohost/plone/my_doc?without_metatag_keywords=1' in text:
+                    text = self.context.getText()
 
-            if additional and is_test is None:
-                # extract words from url page using lynx browser
-                text = commands.getoutput('lynx --dump --nolist %s?qseo_without_additional_keywords=1' % self.context.absolute_url()).lower()
                 if text and text != 'sh: lynx: command not found':
-                    for keyword in additional:
-                        if keyword.lower() not in lower_keywords and re.compile(r'\b%s\b' % keyword, re.I).search(text):
-                            keywords.append(keyword)
-            return ', '.join(keywords)
-        return ''
+                    for meta_keyword in meta_keywords:
+                        if re.compile(r'\b%s\b' % meta_keyword.lower(), re.I).search(text):
+                            filtered_keywords.append(meta_keyword)
+                    meta_keywords = filtered_keywords
+        return ', '.join(meta_keywords)
 
 
Index: quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/keywords.py
===================================================================
--- quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/keywords.py	(revision 1610)
+++ quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/keywords.py	(revision 1624)
@@ -23,42 +23,9 @@
             return ts.utranslate(None, _(u'Keywords list is empty!'), context=self.context)
         # request html page of context object
-        url = '%s?qseo_without_additional_keywords=1' % self.context.absolute_url()
-        #try:
-            #page = urllib.urlopen(url)
-        #except IOError:
-            #return _('Could not find requested page')
+        url = '%s?without_metatag_keywords=1' % self.context.absolute_url()
 
-        #page_html = page.read()
-        #if not page_html:
-            #return _('Page is empty')
-
-        # extract words from body from html page
-
-        # this block work only with valid html
-        #doc = minidom.parseString(page_html)
-        #rootNode = doc.documentElement
-        #bodies = rootNode.getElementsByTagName('body')
-        #if len(bodies) > 0:
-            #body = bodies[0]
-        #else:
-            #return _(u'Invalid page html')
-        #page_words = []
-        #self.walkTextNodes(body, page_words)
-
-        # this block work even with invalid html
-        #pattern = re.compile('<\s*body[^>]*>(.*?)<\s*/\s*body\s*>', re.S|re.M|re.I)
-        #search = pattern.search(page_html)
-        #if search:
-            #body_html = search.group(1)
-        #else:
-            #return _('Invalid html code on page')
-
-        #page_text = self.strip_tags(body_html)
-        #page_words = page_text.lower().split()
-
-        # extract words from url page using lynx browser
+        # extract words from url page using lynx browser (test page by 'url' randered without metatag keywords)
         page_text = commands.getoutput('lynx --dump --nolist %s' % url).lower()
         if page_text and page_text != 'sh: lynx: command not found':
-            #page_words = page_text.lower().split()
             page_text = page_text.decode('utf8')
         else:
Index: quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/templates/seo_context_properties.pt
===================================================================
--- quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/templates/seo_context_properties.pt	(revision 1610)
+++ quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/templates/seo_context_properties.pt	(revision 1624)
@@ -51,5 +51,5 @@
             Item Properties
           </legend>
-  
+
           <div class="field">
             <label i18n:translate="label_page_title_tag" for="seo_title">
@@ -99,5 +99,5 @@
               Override
             </label>
-	    <br />
+            <br />
             <textarea type="text"
                       id="seo_description"
@@ -131,5 +131,5 @@
               Override
             </label>
-	    <br />
+            <br />
             <textarea id="seo_keywords"
                       name="seo_keywords:lines"
@@ -189,5 +189,5 @@
               Override
             </label>
-	    <br />
+            <br />
             <input type="text"
                    id="seo_robots"
@@ -218,5 +218,5 @@
               Override
             </label>
-	    <br />
+            <br />
             <input type="text"
                    id="seo_distribution"
@@ -250,5 +250,5 @@
               Override
             </label>
-	    <br />
+            <br />
             <div tal:content="error">Validation error output</div>
             <input type="text"
@@ -282,5 +282,5 @@
               Override
             </label>
-	    <br />
+            <br />
             <table class="custom-metatags-table"
                    id="datagridwidget-table-seo_custommetatags"
Index: quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/views.py
===================================================================
--- quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/views.py	(revision 1610)
+++ quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/views.py	(revision 1624)
@@ -141,6 +141,7 @@
         return html_comment and html_comment or '' 
 
-    def seo_keywords( self ):
-        """ Generate Keywords from SEO properties.
+    def meta_keywords( self ):
+        """ Generate Meta Keywords from SEO properties (global and local) with Subject,
+            depending on the options in configlet.
         """
         prop_name = 'qSEO_keywords'
@@ -190,4 +191,24 @@
         return keywords
 
+    def seo_keywords( self ):
+        """ Generate SEO Keywords from SEO properties (global merde local).
+        """
+        prop_name = 'qSEO_keywords'
+        context = aq_inner(self.context)
+        keywords = Set([])
+        pprops = getToolByName(context, 'portal_properties')
+        sheet = getattr(pprops, 'seo_properties', None)
+
+        if sheet:
+            settings_use_keywords_sg = sheet.getProperty('settings_use_keywords_sg')
+            settings_use_keywords_lg = sheet.getProperty('settings_use_keywords_lg')
+            global_keywords = Set(sheet.getProperty('additional_keywords', None))
+            local_keywords = Set(context.getProperty(prop_name, None))
+            keywords = global_keywords | local_keywords
+        else:
+            keywords = ''
+
+        return keywords
+
     def seo_canonical( self ):
         """ Generate canonical URL from SEO properties.
Index: quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/configure.zcml
===================================================================
--- quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/configure.zcml	(revision 1610)
+++ quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/configure.zcml	(revision 1624)
@@ -46,6 +46,6 @@
   <adapter
       for="Products.Archetypes.public.BaseObject"
-      provides=".interfaces.IKeywords"
-      factory=".adapters.AdditionalKeywords"
+      provides=".interfaces.IMetaKeywords"
+      factory=".adapters.MetaKeywordsAdapter"
       />
 
Index: quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/interfaces.py
===================================================================
--- quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/interfaces.py	(revision 1610)
+++ quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/interfaces.py	(revision 1624)
@@ -1,8 +1,8 @@
 from zope.interface import Interface
 
-class IKeywords(Interface):
+class IMetaKeywords(Interface):
     """Handle the available keywords.
     """
-    def listKeywords():
+    def getMetaKeywords():
         """Returns all the existing keywords for the current content type.
         """
Index: quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/profiles/default/propertiestool.xml
===================================================================
--- quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/profiles/default/propertiestool.xml	(revision 1610)
+++ quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/profiles/default/propertiestool.xml	(revision 1624)
@@ -83,5 +83,5 @@
    <element value="DC.distribution seo_distribution"/>
    <element value="description seo_description"/>
-   <element value="keywords seo_keywords"/>
+   <element value="keywords meta_keywords"/>
    <element value="robots seo_robots"/>
    <element value="distribution seo_distribution"/>
Index: quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/tests/testQSEOptimizerAdditionalKeywords.py
===================================================================
--- quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/tests/testQSEOptimizerAdditionalKeywords.py	(revision 1610)
+++ quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/tests/testQSEOptimizerAdditionalKeywords.py	(revision 1624)
@@ -49,4 +49,5 @@
 
     def test_listMetaTags_one(self):
+        self.my_doc.setText('<p>foo</p>')
         self.sp.manage_changeProperties(settings_use_keywords_sg=3, settings_use_keywords_lg=2)
         self.my_doc.manage_addProperty('qSEO_keywords', ('foo',), 'lines')
@@ -56,4 +57,5 @@
 
     def test_listMetaTags_two(self):
+        self.my_doc.setText('<p>foo bar</p>')
         self.sp.manage_changeProperties(settings_use_keywords_sg=3, settings_use_keywords_lg=2)
         self.my_doc.manage_addProperty('qSEO_keywords', ('foo', 'bar'), 'lines')
@@ -70,6 +72,6 @@
 
     def test_additional_keywords_in_listMetaTags_one(self):
+        self.my_doc.setText('<p>foo</p>')
         self.sp.manage_changeProperties(settings_use_keywords_sg=3, settings_use_keywords_lg=2)
-        #self.my_doc.setText('<p>foo</p>') # XXX
         self.sp.additional_keywords = ('foo',)
         self.html = str(self.publish(self.portal.id+'/my_doc', self.basic_auth))
@@ -78,6 +80,6 @@
 
     def test_additional_keywords_in_listMetaTags_two(self):
+        self.my_doc.setText('<p>foo bar</p>')
         self.sp.manage_changeProperties(settings_use_keywords_sg=3, settings_use_keywords_lg=2)
-        #self.my_doc.setText('<p>foo bar</p>') # XXX
         self.sp.additional_keywords = ('foo', 'bar')
         self.html = str(self.publish(self.portal.id+'/my_doc', self.basic_auth))
@@ -87,4 +89,5 @@
 
     def setup_testing_render_keywords(self):
+        self.my_doc.setText('<p>global local subject</p>')
         self.sp.additional_keywords = (('global',))
         self.my_doc.manage_addProperty('qSEO_keywords', ('local'), 'lines')
Index: quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/tests/testQSEOptimizerResponse.py
===================================================================
--- quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/tests/testQSEOptimizerResponse.py	(revision 1610)
+++ quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/tests/testQSEOptimizerResponse.py	(revision 1624)
@@ -27,5 +27,5 @@
         self.sp.manage_changeProperties(settings_use_keywords_sg=3, settings_use_keywords_lg=2)
         abs_path = "/%s" % my_doc.absolute_url(1)
-        self.form_data = {'seo_description': 'it is description', 'seo_keywords_override:int': 1, 'seo_custommetatags_override:int': 1,
+        self.form_data = {'seo_description': 'it is description, test keyword1', 'seo_keywords_override:int': 1, 'seo_custommetatags_override:int': 1,
                         'seo_robots_override:int': 1, 'seo_robots': 'ALL', 'seo_description_override:int': 1, 'seo_canonical_override:int': 1,
                         'seo_keywords:list': 'keyword1', 'seo_html_comment': 'no comments',
@@ -65,5 +65,5 @@
 
     def testDescription(self):
-        m = re.match('.*(<meta\s+(?:(?:name="description"\s*)|(?:content="it is description"\s*)){2}/>)', self.html, re.S|re.M)
+        m = re.match('.*(<meta\s+(?:(?:name="description"\s*)|(?:content="it is description, test keyword1"\s*)){2}/>)', self.html, re.S|re.M)
         self.assert_(m, 'Description not set in')
 
@@ -88,4 +88,5 @@
         metatags_order = [t.split(' ')[0] for t in mtop if len(t.split(' '))==2 and t.split(' ')[0] in VIEW_METATAGS]
         m = re.search('.*'.join(['<meta.*name="%s".*/>' %t for t in metatags_order]), self.html, re.S|re.M)
+        #m = re.match('.*'.join(['.*(<meta\s+(?:(?:name="%s"\s*)|(?:content=".*"\s*)){2}/>)' %t for t in metatags_order]), self.html, re.S|re.M)
         self.assert_(m, "Meta tags order not supported.")
 
