Implemented additional files/folders adding
authorHarishankar <v.harishankar@gmail.com>
Wed, 1 Dec 2010 06:51:23 +0000 (12:21 +0530)
committerHarishankar <v.harishankar@gmail.com>
Wed, 1 Dec 2010 06:51:23 +0000 (12:21 +0530)
* Implemented the copying of additional files and folders
* Now checks whether required additional files exist in
  source directory. If found they are copied automatically.
  If not found, user is told to copy them manually.
  Required additional files are:
  search.py - search CGI script to be copied to cgi-bin/
  star.gif and star-grey.gif - star rating images

biaweb_exporter.py
generate_dialog.py
generate_dialog.ui
search.py [new file with mode: 0755]
star-grey.gif [new file with mode: 0644]
star.gif [new file with mode: 0644]
ui_generate_dialog.py

index e824c08..4560181 100644 (file)
@@ -3,6 +3,7 @@
 
 import os
 import os.path
+import sys
 import time
 import sqlite3
 import string
@@ -48,6 +49,63 @@ def html_format_rating (rating):
        rating_str = "".join (items)
        return rating_str
 
+# function to copy additional files and folders to the destination path
+def copy_files_folders (conf, files_to_copy, folders_to_copy):
+       # create the cgi-bin directory and try to copy search.py into the destination directory if possible
+       # otherwise user must copy it manually
+       search_script_path = os.path.join (sys.path[0], "search.py")
+       if os.path.exists (search_script_path):
+               try:
+                       os.mkdir (os.path.join (conf[5], "cgi-bin"))
+                       shutil.copy2 (search_script_path, os.path.join(conf[5], "cgi-bin"))
+               except IOError, OSError:
+                       return False
+
+       # try to copy the star rating images  to destination directory if possible
+       # otherwise user must copy it manually
+       rating_img_star = os.path.join (sys.path[0], "star.gif")
+       rating_img_greystar = os.path.join (sys.path[0], "star-grey.gif")
+       if os.path.exists (rating_img_star):
+               try:
+                       shutil.copy2 (rating_img_star, conf[5])
+               except IOError, OSError:
+                       return False
+       if os.path.exists (rating_img_greystar):
+               try:
+                       shutil.copy2 (rating_img_greystar, conf[5])
+               except IOError, OSError:
+                       return False
+
+       # additional files to copy
+
+       # first copy files
+       # check if files to copy is not empty
+       if files_to_copy <> []:
+               for src, dest in files_to_copy:
+                       # get full path from relative path in dest
+                       full_dest = os.path.join (conf[5], dest)
+                       try:
+                               shutil.copy2 (src, full_dest)
+                       except IOError, OSError:
+                               return False
+
+       # additional folders to copy
+
+       # now copy the folders
+       if folders_to_copy <> []:
+               for src, dest in folders_to_copy:
+                       # get full path from relative path in dest
+                       full_dest = os.path.join (conf[5], dest)
+                       try:
+                               shutil.copytree (src, full_dest)
+                       except IOError, OSError:
+                               return False
+
+       # finally return true
+       return True
+
+
+
 # function to generate article pages
 def generate_article_pages (dbname, conf, templates, category_str, bestrated_str):
        # main template
@@ -273,5 +331,10 @@ def generate_site (dbname, files_to_copy, folders_to_copy, search_type_full=True
        if ret == False:
                return False
 
+       # copy other files/folders into the destination path
+       ret = copy_files_folders (conf, files_to_copy, folders_to_copy)
+       if ret == False:
+               return False
+
        # finally when all is successfully done return true
        return True
index dc0448b..e236451 100644 (file)
@@ -2,6 +2,7 @@
 # Generate site dialog
 
 import PyQt4
+import sys
 import os
 import os.path
 import ui_generate_dialog
@@ -12,9 +13,45 @@ class GenerateDialog (PyQt4.QtGui.QDialog, ui_generate_dialog.Ui_SiteGenerateDia
                PyQt4.QtGui.QDialog.__init__ (self, master)
                self.setupUi (self)
 
+               # update the status of required additional files to be copied to
+               # the destination directory and warn the user accordingly
+               self.set_required_files_status ()
+
                # set the database
                self.current_db = currentdb
 
+       # function to set the status message of the required additional files to be copied to
+       # the destination directory. If any required additional file is missing in the script
+       # path then warn the user to copy those files manually to the destination directory
+       def set_required_files_status (self):
+               search_script_path = os.path.join (sys.path[0], "search.py")
+               star_image_path = os.path.join (sys.path[0], "star.gif")
+               stargrey_image_path = os.path.join (sys.path[0], "star-grey.gif")
+
+               # if search.py exists in script directory
+               if os.path.exists (search_script_path):
+                       self.status_search_py.setText ('<span style="color:darkgreen;">will be \
+                       automatically copied to destination dir</span>')
+               else:
+                       self.status_search_py.setText ('<span style="color:darkred;">cannot be found.\
+                       You must copy it manually to cgi-bin</span>')
+
+               # if star.gif exists in script directory
+               if os.path.exists (star_image_path):
+                       self.status_star_gif.setText ('<span style="color:darkgreen;">will be \
+                       automatically copied to destination dir</span>')
+               else:
+                       self.status_star_gif.setText ('<span style="color:darkred;">Cannot be found. \
+                       You must copy it manually to destination dir</span')
+
+               # if star-grey.gif exists in script directory
+               if os.path.exists (stargrey_image_path):
+                       self.status_stargrey_gif.setText ('<span style="color:darkgreen;">will be \
+                       automatically copied to destination dir</span>')
+               else:
+                       self.status_stargrey_gif.setText ('<span style="color:darkred;">cannot be found. \
+                       You must copy it manually to destination dir</span')
+
        # to return the list of items from a tree widget
        def get_list_from_tree (self, treewidget):
                lstfiles = []
index 4544906..9ba6fc9 100644 (file)
@@ -26,7 +26,7 @@
    <string>Generate Website</string>
   </property>
   <layout class="QGridLayout" name="gridLayout_2">
-   <item row="0" column="0" colspan="3">
+   <item row="0" column="0" colspan="4">
     <widget class="QLabel" name="label">
      <property name="text">
       <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
 p, li { white-space: pre-wrap; }
 &lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans'; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt;
 &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600; color:#55007f;&quot;&gt;Important Information&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;This will generate your website in the destination directory specified in the site configuration dialog. The entire directory tree will be re-created from scratch and any manual changes you made to the generated files will be gone!&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; &lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;You need to re-copy the additional files/folders you require in the destination folder (e.g. the rating (star) image files or directories, the search.py CGI script) every time you generate the site. Specify the files/folders to copy to generated site.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+&lt;p style=&quot; margin-top:8px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;This will generate your website in the destination directory configured. The directory tree will be re-created from scratch and any manual changes you made to the generated files will be destroyed!&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;You need to re-copy the additional files/folders you require in the destination folder (e.g. image directories) every time you generate the site. Specify the files/folders to copy to generated site.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
      </property>
      <property name="wordWrap">
       <bool>true</bool>
      </property>
     </widget>
    </item>
-   <item row="1" column="0" colspan="3">
+   <item row="1" column="0">
+    <widget class="QLabel" name="label_4">
+     <property name="text">
+      <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans'; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Required additional files&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="0">
+    <widget class="QLabel" name="label_5">
+     <property name="text">
+      <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans'; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;search.py&lt;/span&gt; (search CGI script):&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="1" colspan="3">
+    <widget class="QLabel" name="status_search_py">
+     <property name="text">
+      <string>status</string>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="0">
+    <widget class="QLabel" name="label_6">
+     <property name="text">
+      <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans'; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;star.gif&lt;/span&gt; (star rating image):&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="1" colspan="3">
+    <widget class="QLabel" name="status_star_gif">
+     <property name="text">
+      <string>status</string>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="0">
+    <widget class="QLabel" name="label_7">
+     <property name="text">
+      <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans'; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;star-grey.gif&lt;/span&gt; (star rating image):&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="1" colspan="3">
+    <widget class="QLabel" name="status_stargrey_gif">
+     <property name="text">
+      <string>status</string>
+     </property>
+    </widget>
+   </item>
+   <item row="5" column="0" colspan="4">
     <widget class="QTabWidget" name="tabWidget">
      <property name="currentIndex">
       <number>0</number>
@@ -134,7 +198,7 @@ p, li { white-space: pre-wrap; }
      </widget>
     </widget>
    </item>
-   <item row="2" column="0">
+   <item row="6" column="0" colspan="2">
     <widget class="QGroupBox" name="groupBox">
      <property name="title">
       <string>Search index type</string>
@@ -163,7 +227,7 @@ p, li { white-space: pre-wrap; }
      </layout>
     </widget>
    </item>
-   <item row="3" column="1">
+   <item row="6" column="2">
     <widget class="QPushButton" name="generate_site">
      <property name="text">
       <string>&amp;Generate site</string>
@@ -173,7 +237,7 @@ p, li { white-space: pre-wrap; }
      </property>
     </widget>
    </item>
-   <item row="3" column="2">
+   <item row="6" column="3">
     <widget class="QPushButton" name="close">
      <property name="text">
       <string>&amp;Close</string>
diff --git a/search.py b/search.py
new file mode 100755 (executable)
index 0000000..cc5ab6e
--- /dev/null
+++ b/search.py
@@ -0,0 +1,395 @@
+#!/usr/bin/env python
+
+# hari's search engine front-end
+# this program queries the search index created by hari's search index creator application
+
+import string
+import cPickle
+import cgi
+import os
+import os.path
+import time
+
+# -----------------------------------------------------------
+# configuration settings
+# -----------------------------------------------------------
+
+# script start time
+strttime = time.time ()
+
+# path to the search database index file - edit as necessary
+search_db_path = "searchwords.idx"
+
+# path to file containing the "stop words" words which should be excluded from the query
+stopwords_list = """$
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+a
+able
+about
+after
+again
+all
+almost
+already
+also
+although
+am
+an
+and
+another
+any
+are
+are
+around
+as
+at
+b
+based
+be
+because
+been
+before
+being
+between
+both
+bring
+but
+by
+c
+came
+can
+com
+come
+comes
+could
+d
+did
+do
+does
+doing
+done
+e
+each
+eight
+else
+etc
+even
+every
+f
+five
+for
+four
+from
+g
+get
+gets
+getting
+go
+going
+got
+h
+had
+has
+have
+he
+he
+her
+here
+him
+himself
+his
+how
+however
+href
+http
+i
+if
+in
+including
+into
+is
+it
+it
+its
+j
+just
+k
+kb
+know
+l
+like
+looks
+m
+mailto
+make
+making
+many
+may
+mb
+me
+means
+might
+more
+more
+most
+move
+mr
+much
+must
+my
+n
+need
+needs
+never
+nice
+nine
+no
+not
+now
+o
+of
+often
+oh
+ok
+on
+on
+one
+only
+or
+org
+other
+our
+out
+over
+own
+p
+piece
+q
+r
+rather
+re
+really
+s
+said
+same
+say
+says
+see
+seven
+several
+she
+should
+since
+single
+six
+so
+so
+some
+something
+still
+stuff
+such
+t
+take
+ten
+than
+that
+the
+their
+them
+them
+then
+there
+there
+these
+they
+they
+thing
+things
+this
+those
+three
+through
+to
+too
+took
+two
+u
+under
+up
+us
+use
+used
+using
+usual
+v
+ve
+very
+via
+w
+want
+was
+way
+we
+we
+well
+were
+what
+when
+where
+whether
+which
+while
+whilst
+who
+why
+will
+with
+within
+would
+x
+y
+yes
+yet
+you
+your
+z""".split ("\n")
+
+# first print the header and the HTML code
+print "Content-type: text/html; charset=utf-8"
+print """
+<html>
+<head>
+       <title>Search Results</title>
+</head>
+<body>
+<h1>Search results</h1>
+<hr>
+"""
+
+# check whether the search database exists at all
+if not os.path.exists (search_db_path) and not os.path.isfile (search_db_path):
+       print "Search database file seems to be missing. Cannot search."
+       print "</body>"
+       print "</html>"
+       sys.exit ()
+
+frm = cgi.FieldStorage ()
+
+# if the form has not been submitted, then ask for it to be submitted
+if not frm.has_key ("fromsearch") or frm.getfirst("query") == "" :
+       print "No search query defined."
+       print "</body>"
+       print "</html>"
+else:
+       # get the query
+       raw_query = frm.getfirst ("query").strip ().lower ()
+       # get the mode of the query - AND or NOT
+       mode = int (frm.getfirst ("criteria"))
+       
+       # split the terms
+       raw_query_list = raw_query.split ()
+               
+       # get the database of search terms
+       try:
+               search_db = cPickle.load (open (search_db_path, "rb"))
+       except:
+               print "Error reading search database: might not valid."
+       
+       # if the number of search words is too much
+       if len (raw_query_list) > 5:
+               print "<p>Too many terms. Try fewer search terms (avoid common words like a, and, or, in).</p>"
+               print "</body>"
+               print "</html>"
+               sys.exit ()
+               
+       
+       # display the list of search terms
+       print "Search terms: ",
+       
+       # search words set
+       search_words = set ()
+       
+       # add the search words to the set
+       for raw_word in raw_query_list:
+               # strip the raw word of all non-alphabetic characters at the beginnning and end
+               word = raw_word.strip (":;?!_<>,.+-\"'=`!@#$%^&*()[]{}/= \n\r\t")
+               
+               # only if the word is not in the stopwords list add it to the query
+               if not word in stopwords_list:
+                       print "<b>" + word + "</b>, ",
+                       search_words.add (word)
+               # just display the word with a strike-through to indicate its non-inclusion
+               else:
+                       print "<strike>" + word + "</strike>, ",
+       
+       # if there are no specific terms found
+       if len(search_words) == 0:
+               print "<p>Search terms are too broad and commonly used words. Try searching with at least one specific term.</p>"
+               print "</body>"
+               print "</html>"
+               sys.exit ()
+       
+       # get the search results
+       search_results = set ()
+       flagfirst = True
+       
+       # print search mode
+       print "<p>Search mode: ",
+       if (mode == 1):
+               print "documents containing all search terms</p>"
+       else:
+               print "documents containing any of the search terms</p>"
+       
+       # get the words found in the database
+       for word in search_words:
+               # if the word is found
+               if search_db.has_key (word):
+                       if (flagfirst == True):
+                               search_results = search_db[word]
+                               flagfirst = False
+                       else:
+                               # AND mode
+                               if (mode == 1):
+                                       search_results = search_results & search_db[word]
+                               # Assume OR mode
+                               else:
+                                       search_results = search_results | search_db[word]
+               # if word is not found and the mode is AND, then return empty result
+               else:
+                       if (mode == 1):
+                               search_results.clear ()
+                               break
+       
+       # display the results
+       
+       # if no results are found
+       if len (search_results) == 0:
+               print "<p>No pages matched your query.</p>"
+       else:
+               # display the result
+               print "<h2>Documents found</h2>"
+               print "<ul>"
+               for title, url in search_results:
+                       print '<li><a href="' + url + '">' + title + '</a>'
+               print "</ul>"
+
+# print the script execution time
+endtime = time.time ()
+dif = endtime - strttime
+
+print "<hr>"
+print "<small>Script execution time: ",
+print dif,
+print "sec</small>"
+print "</body>"
+print "</html>"
diff --git a/star-grey.gif b/star-grey.gif
new file mode 100644 (file)
index 0000000..ca97b2d
Binary files /dev/null and b/star-grey.gif differ
diff --git a/star.gif b/star.gif
new file mode 100644 (file)
index 0000000..2370eef
Binary files /dev/null and b/star.gif differ
index fab5abf..f0f9517 100644 (file)
@@ -2,7 +2,7 @@
 
 # Form implementation generated from reading ui file 'generate_dialog.ui'
 #
-# Created: Tue Nov 30 14:05:23 2010
+# Created: Wed Dec  1 12:19:07 2010
 #      by: PyQt4 UI code generator 4.7.4
 #
 # WARNING! All changes made in this file will be lost!
@@ -20,7 +20,28 @@ class Ui_SiteGenerateDialog(object):
         self.label = QtGui.QLabel(SiteGenerateDialog)
         self.label.setWordWrap(True)
         self.label.setObjectName("label")
-        self.gridLayout_2.addWidget(self.label, 0, 0, 1, 3)
+        self.gridLayout_2.addWidget(self.label, 0, 0, 1, 4)
+        self.label_4 = QtGui.QLabel(SiteGenerateDialog)
+        self.label_4.setObjectName("label_4")
+        self.gridLayout_2.addWidget(self.label_4, 1, 0, 1, 1)
+        self.label_5 = QtGui.QLabel(SiteGenerateDialog)
+        self.label_5.setObjectName("label_5")
+        self.gridLayout_2.addWidget(self.label_5, 2, 0, 1, 1)
+        self.status_search_py = QtGui.QLabel(SiteGenerateDialog)
+        self.status_search_py.setObjectName("status_search_py")
+        self.gridLayout_2.addWidget(self.status_search_py, 2, 1, 1, 3)
+        self.label_6 = QtGui.QLabel(SiteGenerateDialog)
+        self.label_6.setObjectName("label_6")
+        self.gridLayout_2.addWidget(self.label_6, 3, 0, 1, 1)
+        self.status_star_gif = QtGui.QLabel(SiteGenerateDialog)
+        self.status_star_gif.setObjectName("status_star_gif")
+        self.gridLayout_2.addWidget(self.status_star_gif, 3, 1, 1, 3)
+        self.label_7 = QtGui.QLabel(SiteGenerateDialog)
+        self.label_7.setObjectName("label_7")
+        self.gridLayout_2.addWidget(self.label_7, 4, 0, 1, 1)
+        self.status_stargrey_gif = QtGui.QLabel(SiteGenerateDialog)
+        self.status_stargrey_gif.setObjectName("status_stargrey_gif")
+        self.gridLayout_2.addWidget(self.status_stargrey_gif, 4, 1, 1, 3)
         self.tabWidget = QtGui.QTabWidget(SiteGenerateDialog)
         self.tabWidget.setObjectName("tabWidget")
         self.tab = QtGui.QWidget()
@@ -57,7 +78,7 @@ class Ui_SiteGenerateDialog(object):
         self.additional_folders.setObjectName("additional_folders")
         self.gridLayout_4.addWidget(self.additional_folders, 1, 0, 1, 3)
         self.tabWidget.addTab(self.tab_2, "")
-        self.gridLayout_2.addWidget(self.tabWidget, 1, 0, 1, 3)
+        self.gridLayout_2.addWidget(self.tabWidget, 5, 0, 1, 4)
         self.groupBox = QtGui.QGroupBox(SiteGenerateDialog)
         self.groupBox.setObjectName("groupBox")
         self.gridLayout = QtGui.QGridLayout(self.groupBox)
@@ -70,14 +91,14 @@ class Ui_SiteGenerateDialog(object):
         self.keywordindex.setChecked(False)
         self.keywordindex.setObjectName("keywordindex")
         self.gridLayout.addWidget(self.keywordindex, 0, 1, 1, 1)
-        self.gridLayout_2.addWidget(self.groupBox, 2, 0, 1, 1)
+        self.gridLayout_2.addWidget(self.groupBox, 6, 0, 1, 2)
         self.generate_site = QtGui.QPushButton(SiteGenerateDialog)
         self.generate_site.setDefault(True)
         self.generate_site.setObjectName("generate_site")
-        self.gridLayout_2.addWidget(self.generate_site, 3, 1, 1, 1)
+        self.gridLayout_2.addWidget(self.generate_site, 6, 2, 1, 1)
         self.close = QtGui.QPushButton(SiteGenerateDialog)
         self.close.setObjectName("close")
-        self.gridLayout_2.addWidget(self.close, 3, 2, 1, 1)
+        self.gridLayout_2.addWidget(self.close, 6, 3, 1, 1)
 
         self.retranslateUi(SiteGenerateDialog)
         self.tabWidget.setCurrentIndex(0)
@@ -106,9 +127,31 @@ class Ui_SiteGenerateDialog(object):
 "p, li { white-space: pre-wrap; }\n"
 "</style></head><body style=\" font-family:\'Sans\'; font-size:10pt; font-weight:400; font-style:normal;\">\n"
 "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-weight:600; color:#55007f;\">Important Information</span></p>\n"
-"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">This will generate your website in the destination directory specified in the site configuration dialog. The entire directory tree will be re-created from scratch and any manual changes you made to the generated files will be gone!</p>\n"
-"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"> </p>\n"
-"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-style:italic;\">You need to re-copy the additional files/folders you require in the destination folder (e.g. the rating (star) image files or directories, the search.py CGI script) every time you generate the site. Specify the files/folders to copy to generated site.</span></p></body></html>", None, QtGui.QApplication.UnicodeUTF8))
+"<p style=\" margin-top:8px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">This will generate your website in the destination directory configured. The directory tree will be re-created from scratch and any manual changes you made to the generated files will be destroyed!</p>\n"
+"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-style:italic;\">You need to re-copy the additional files/folders you require in the destination folder (e.g. image directories) every time you generate the site. Specify the files/folders to copy to generated site.</span></p></body></html>", None, QtGui.QApplication.UnicodeUTF8))
+        self.label_4.setText(QtGui.QApplication.translate("SiteGenerateDialog", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
+"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
+"p, li { white-space: pre-wrap; }\n"
+"</style></head><body style=\" font-family:\'Sans\'; font-size:10pt; font-weight:400; font-style:normal;\">\n"
+"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-weight:600;\">Required additional files</span></p></body></html>", None, QtGui.QApplication.UnicodeUTF8))
+        self.label_5.setText(QtGui.QApplication.translate("SiteGenerateDialog", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
+"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
+"p, li { white-space: pre-wrap; }\n"
+"</style></head><body style=\" font-family:\'Sans\'; font-size:10pt; font-weight:400; font-style:normal;\">\n"
+"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-weight:600;\">search.py</span> (search CGI script):</p></body></html>", None, QtGui.QApplication.UnicodeUTF8))
+        self.status_search_py.setText(QtGui.QApplication.translate("SiteGenerateDialog", "status", None, QtGui.QApplication.UnicodeUTF8))
+        self.label_6.setText(QtGui.QApplication.translate("SiteGenerateDialog", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
+"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
+"p, li { white-space: pre-wrap; }\n"
+"</style></head><body style=\" font-family:\'Sans\'; font-size:10pt; font-weight:400; font-style:normal;\">\n"
+"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-weight:600;\">star.gif</span> (star rating image):</p></body></html>", None, QtGui.QApplication.UnicodeUTF8))
+        self.status_star_gif.setText(QtGui.QApplication.translate("SiteGenerateDialog", "status", None, QtGui.QApplication.UnicodeUTF8))
+        self.label_7.setText(QtGui.QApplication.translate("SiteGenerateDialog", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
+"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
+"p, li { white-space: pre-wrap; }\n"
+"</style></head><body style=\" font-family:\'Sans\'; font-size:10pt; font-weight:400; font-style:normal;\">\n"
+"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-weight:600;\">star-grey.gif</span> (star rating image):</p></body></html>", None, QtGui.QApplication.UnicodeUTF8))
+        self.status_stargrey_gif.setText(QtGui.QApplication.translate("SiteGenerateDialog", "status", None, QtGui.QApplication.UnicodeUTF8))
         self.label_2.setText(QtGui.QApplication.translate("SiteGenerateDialog", "Additional files to add to destination", None, QtGui.QApplication.UnicodeUTF8))
         self.addfile.setText(QtGui.QApplication.translate("SiteGenerateDialog", "&Add file", None, QtGui.QApplication.UnicodeUTF8))
         self.removefile.setText(QtGui.QApplication.translate("SiteGenerateDialog", "&Remove", None, QtGui.QApplication.UnicodeUTF8))