changeset 0:d164d12d06b8

initial version of arnica (image gallery parser and slideshow action)
author Reimar Bauer <rb.proj AT googlemail DOT com>
date Fri, 07 Mar 2008 15:48:15 +0100
parents
children 33d03349c532
files data/plugin/action/arnica_slides.py data/plugin/parser/text_x_arnica.py htdocs/common/arnica/arnica_back.png htdocs/common/arnica/arnica_disabled.png htdocs/common/arnica/arnica_first.png htdocs/common/arnica/arnica_first_disabled.png htdocs/common/arnica/arnica_last.png htdocs/common/arnica/arnica_last_disabled.png htdocs/common/arnica/arnica_next.png htdocs/common/arnica/arnica_next_disabled.png htdocs/common/arnica/arnica_previous.png htdocs/common/arnica/arnica_to_bak.png htdocs/common/arnica/arnica_to_full.png htdocs/common/arnica/arnica_to_left.png htdocs/common/arnica/arnica_to_right.png htdocs/common/arnica/arnica_to_slide.png
diffstat 16 files changed, 1113 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/plugin/action/arnica_slides.py	Fri Mar 07 15:48:15 2008 +0100
@@ -0,0 +1,464 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - arnica_slides Action macro
+    This action macro is used to rotate, move to bak or to slide through the images from arnica
+
+    based on gallery2image by ReimarBauer 2005-2008
+    
+    @copyright: 2008 by MoinMoin:ReimarBauer
+    @license: GNU GPL, see COPYING for details.
+"""
+Dependencies = []
+import os
+from MoinMoin import  wikiutil
+from MoinMoin.Page import Page
+from MoinMoin.action import AttachFile
+from MoinMoin.formatter.text_html import Formatter
+from MoinMoin.util import filesys
+from MoinMoin.action import ActionBase
+
+try:
+    import Image
+except ImportError:
+    Image = None
+
+action_name = __name__.split('.')[-1]
+
+class arnica_slides(ActionBase):
+    """ arnica_slides page action
+
+    Note: the action name is the class name
+    """
+    def __init__(self, request, pagename):
+        ActionBase.__init__(self, pagename, request)
+        self.request = request
+        self.pagename = pagename
+        self.page = Page(request, pagename)
+        self.method = 'POST'
+        self.enctype = 'multipart/form-data'
+
+    def is_excluded(self):
+        """ Return True if action is excluded """
+        return self.actionname in self.cfg.actions_excluded
+
+    def is_allowed(self):
+        """ Return True if read access is allowed """
+        may = self.request.user.may
+        return may.read(self.pagename)
+
+    def get_path_url(self, request, pagename, attachment_path):
+        """ Returns attachment path and it's url 
+        @param request: request object
+        @pagename: pagename of attachments
+        @attachment_path: path to attachment
+        """
+        url = AttachFile.getAttachUrl(pagename, '', request)
+        url = url.replace('//', '/')
+        return attachment_path, url
+
+    def option_list(self, this_image, pagename, text, request):
+        """ generates the pulldown option list
+        @param this_image: selected image  on top
+        @param pagename: pagename of attachments
+        @param text: array of filenames
+        @param request: request object
+        """
+        txt = ''
+
+        for filename in text:
+            name = AttachFile.getAttachUrl(pagename, filename, request)
+            if name == this_image:
+                txt += '<option selected value="%(name)s">%(alias)s' % {
+                    "name": this_image,
+                    "alias": filename.replace('tmp.', '')}
+            else:
+                txt += '<option value="%(name)s">%(alias)s' % {
+                    "name": this_image,
+                    "alias": filename.replace('tmp.', '')}
+
+        return txt
+
+    def html_js(self, request, this_image, counter):
+        """ javscript for the slides 
+        @param request: request object
+        @param this_image:  url of image to start
+        @param counter: index position of this_image
+        """
+
+        html = '''
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Original:  Ricocheting (ricocheting@hotmail.com) -->
+<!-- Web Site:  http://www.ricocheting.com -->
+
+<!-- This script and many more are available free online at -->
+<!-- The JavaScript Source!! http://javascript.internet.com -->
+
+<!-- Modifications by MoinMoin:ReimarBauer -->
+<!-- 2005-10-29 -->
+<!-- Many thanks to Ricocheting, it is much easier as my own one. I like it -->
+<!-- Some code added and replaced for the MoinMoin:arnica parser-->
+
+
+<!-- Begin 
+
+var rotate_delay = 5; // delay in milliseconds (5000 = 5 secs)
+var current = %(counter)s;
+var theImages = new Array();
+var thewebImages =  new Array();
+
+function arnica_preload() {
+   var list = document.slideform.webnail_list.value;
+   var value = list.split(","); 
+   var n = value.length;
+   
+   for (i = 0; i <  n-1; i++){
+       theImages[i] = new Image();
+       theImages[i].src = value[i];
+   }   
+   thewebImages = theImages;
+} 
+
+function arnica_getserver() {
+     var value = document.URL;
+     var text = value.split("/");
+     return text[0]+'//'+text[2];
+}     
+
+function arnica_show_image(image) {
+    return arnica_getserver() + '%(htdocs)s' + '/common/arnica/' + image;
+} 
+
+function arnica_add_comments() {
+  var alias_text = document.slideform.alias.value;
+  var exif_date_text = document.slideform.exif_date.value;
+  var index = document.slideform.slide.selectedIndex;
+  var alias = alias_text.split("!,!");
+  var exif = exif_date_text.split(",");
+  document.getElementById("arnica_alias_text").innerHTML = alias[index];
+  document.getElementById("arnica_exif_date_text").innerHTML = exif[index];
+}
+
+function arnica_next_slide() {
+   if (document.slideform.slide[current+1]) {
+      document.images.show.src = theImages[current+1].src;
+      document.slideform.slide.selectedIndex = ++current;
+      arnica_add_comments();
+   }
+   else arnica_first_slide();
+   document.getElementById("arnica_first_slide").innerHTML = '<img src="'+arnica_show_image('arnica_first.png')+'" onclick="arnica_first_slide();" name="fs"  title="first slide" >';
+   document.getElementById("arnica_last_slide").innerHTML = '<img src="'+arnica_show_image('arnica_last.png')+'" onclick="arnica_last_slide();" name="fs"  title="last slide" >';
+}
+
+function arnica_previous_slide() {
+   if (current-1 >= 0) {
+      document.images.show.src = theImages[current-1].src;  
+      document.slideform.slide.selectedIndex = --current;
+      arnica_add_comments(); 
+   }
+   else arnica_last_slide();
+   document.getElementById("arnica_first_slide").innerHTML = '<img src="'+arnica_show_image('arnica_first.png')+'" onclick="arnica_first_slide();" name="fs"  title="first slide" >';
+   document.getElementById("arnica_last_slide").innerHTML = '<img src="'+arnica_show_image('arnica_last.png')+'" onclick="arnica_last_slide();" name="fs"  title="last slide" >';
+}
+
+function arnica_first_slide() {
+   current = 0;
+   document.images.show.src = theImages[0].src;  
+   document.slideform.slide.selectedIndex = 0;
+   arnica_add_comments();
+   document.getElementById("arnica_first_slide").innerHTML = '<img src="'+arnica_show_image('arnica_first_disabled.png')+'" title="first slide" >';
+   document.getElementById("arnica_last_slide").innerHTML = '<img src="'+arnica_show_image('arnica_last.png')+'" onclick="arnica_last_slide();" name="fs"  title="last slide" >';
+}
+
+function arnica_last_slide() {
+   current = document.slideform.slide.length-1;
+   document.images.show.src = theImages[current].src; 
+   document.slideform.slide.selectedIndex = current;
+   arnica_add_comments();
+   document.getElementById("arnica_first_slide").innerHTML = '<img src="'+arnica_show_image('arnica_first.png')+'" onclick="arnica_first_slide();" name="fs"  title="first slide" >';
+   document.getElementById("arnica_last_slide").innerHTML = '<img src="'+arnica_show_image('arnica_last_disabled.png')+'" title="last slide" >';
+}
+
+function arnica_ap(text) {
+   document.slideform.slidebutton.value = (text == "Stop") ? "Start" : "Stop";
+   arnica_rotate();
+}
+
+function arnica_change() {
+   current = document.slideform.slide.selectedIndex;
+   document.images.show.src = theImages[current].src; 
+   arnica_add_comments(); 
+   document.getElementById("arnica_first_slide").innerHTML = '<img src="'+arnica_show_image('arnica_first.png') +'" onclick="arnica_first_slide();" name="fs"  title="first slide" >';
+   document.getElementById("arnica_last_slide").innerHTML = '<img src="'+arnica_show_image('arnica_last.png')+'" onclick="arnica_last_slide();" name="fs"  title="last slide" >';
+}
+
+function arnica_rotate() {
+   if (document.slideform.slidebutton.value == "Stop") {
+      current = (current == document.slideform.slide.length-1) ? 0 : current+1;
+      document.images.show.src = theImages[current].src; 
+      document.slideform.slide.selectedIndex = current;
+      arnica_add_comments(); 
+      document.getElementById("arnica_first_slide").innerHTML = '<img src="'+arnica_show_image('arnica_first.png')+'" onclick="arnica_first_slide();" name="fs"  title="first slide" >';
+      document.getElementById("arnica_last_slide").innerHTML = '<img src="'+arnica_show_image('arnica_last.png')+'" onclick="arnica_last_slide();" name="fs"  title="last slide" >';
+      rotate_delay = document.slideform.duration.value * 1000.;
+      window.setTimeout("arnica_rotate()", rotate_delay);
+   }
+}
+//  End -->
+</script> ''' % {
+  'htdocs': request.cfg.url_prefix_static,
+  'counter': counter}
+
+        return html
+
+    def html_slideform(self, request, pagename, alias, exif_date, target, idx):
+        """ html code for the slideform
+        @param request: request object
+        @param pagename: pagename where the attachments are located
+        @param url_wiki_page: 
+        @param alias: text alias for filename
+        @param exif_date:  date information 
+        @param target: all images 
+        @param idx:  index position of the image
+        """
+
+        attachment_path = AttachFile.getAttachDir(request, pagename)
+        static_path, static_url = self.get_path_url(request, pagename, attachment_path )
+
+        option_webnail = self.option_list(static_url + target[idx], pagename, target, request)
+        static_path, static_url = self.get_path_url(request, pagename, attachment_path)
+
+        inner_table_style = ' style="border-style:none; margin:10px;"'
+
+        this_webnail_list = ''
+        for name in target:
+            this_webnail_list += static_url + name + ','
+            html = '''
+<form name=slideform method="POST">
+   <input type="hidden" name="flag" value="webnail">
+   <input type="hidden" name="webnail_list" value='%(this_webnail_list)s'>
+   <input type="hidden" name="webnail_name" value='%(this_webnail_name)s'>
+   <input type="hidden" name="alias" value='%(this_alias_list)s'>
+   <input type="hidden" name="exif_date" value='%(this_exif_date_list)s'>
+   <BR>
+   <table%(tablestyle)s>
+    <tr>
+     <td style="border-style:none" bgcolor="#C0C0C0"><strong>Slide: </strong></td>
+     <td style="border-style:none" bgcolor="#C0C0C0">
+       <select name="slide" onChange="arnica_change();" >
+         %(option_webnails)s
+       </select>
+     </td>
+     <td style="border-style:none" bgcolor="#C0C0C0">
+      <input type="button" name="slidebutton" onClick="arnica_ap(this.value);" value="Start" title="AutoPlay">
+     </td>
+     <td style="border-style:none" bgcolor="#C0C0C0">
+      <strong>Duration (sec): </strong>
+     </td>
+     <td style="border-style:none" bgcolor="#C0C0C0">
+      <input type="input" name="duration" value="3.0" size="3">
+     </td>
+   </tr>
+   <tr>
+     <td style="border-style:none" colspan="5" align="center" bgcolor="#C0C0C0">
+     <SPAN id="arnica_first_slide"><img src="%(server)s%(htdocs)s/common/arnica/arnica_first.png" onclick="arnica_first_slide();" name="fs"  title="first slide" ></SPAN>
+     <img src="%(server)s%(htdocs)s/common/arnica/arnica_previous.png" onclick="arnica_previous_slide();"  title="previous slide" >
+     <img src="%(server)s%(htdocs)s/common/arnica/arnica_next.png" onClick="arnica_next_slide();"  title="next slide" >
+     <SPAN id="arnica_last_slide"><img src="%(server)s%(htdocs)s/common/arnica/arnica_last.png" onClick="arnica_last_slide();"  title="last slide" ></SPAN>
+     <input type="image" value="submit" src="%(server)s%(htdocs)s/common/arnica/arnica_back.png" title="return to %(pagename)s">
+     </td>
+   </tr>
+   <tr>
+    <td style="border-style:none" colspan="5" align="center" bgcolor="#C0C0C0">
+     <img src="%(server)s/%(this_image)s" name="show">
+    </td>
+   </tr>
+   <tr valign="center">
+    <td style="border-style:none"colspan="5" bgcolor="#C0C0C0" align="left">
+     <P><SPAN id="arnica_alias_text">%(this_alias_text)s</SPAN></P>
+    </td></tr>
+   <tr valign="center">
+    <td style="border-style:none" colspan="5" bgcolor="#C0C0C0" align="left">  
+     <P><SPAN id="arnica_exif_date_text">%(this_exif_date_text)s</SPAN></P>
+    </td>
+  </tr>
+</table>
+</form>
+''' % {
+"server": request.getQualifiedURL(),
+"htdocs": request.cfg.url_prefix_static,
+"base_url": request.getScriptname(),
+"this_webnail_list": this_webnail_list,
+"this_webnail_name": ','.join(target),
+"this_alias_text": wikiutil.escape(alias[idx], quote=1),
+"this_alias_list": wikiutil.escape('!,!'.join(alias), quote=1),
+"this_exif_date_text": wikiutil.escape(exif_date[idx], quote=1),
+"this_exif_date_list": wikiutil.escape(','.join(exif_date), quote=1),
+
+"this_image": static_url + target[idx], # AttachFile.getAttachUrl(pagename, target[idx], request),
+"pagename": pagename,
+"tablestyle": inner_table_style,
+"option_webnails": option_webnail,
+}
+        return html
+
+    def do_action(self):
+        """ Do the action and either return error msg or None, if there was no error. """
+        return None
+
+    def do_action_finish(self):
+        """ Do the action and either return error msg or None, if there was no error. """
+        return None
+
+    def image_rotate(self, file, webf, thumbf, angle, img_type):
+        """ rotates the image and dependent images
+        
+        @param file: the name of the attachment
+        @param webf: the name of the webnail
+        @param thumbf: the name of the thumbnail
+        @param angle: the angle to rotate to
+        @param img_type: type of image PNG or JPEG
+        """
+        _ = self.request.getText
+        if not Image:
+            msg = _('The action %(action)s needs python imaging library (PIL) installed' % {'action': action_name})
+            self.request.theme.add_msg(msg, "error")
+            Page(self.request, self.pagename).send_page()
+            return
+        # image
+        im = Image.open(file)
+        os.remove(file)
+        im.rotate(angle).save(file, img_type)
+
+        # image becomes webnail
+        nim = Image.open(file)
+        nim.thumbnail((640, 640), Image.ANTIALIAS)
+        os.remove(webf)
+        nim.save(webf, img_type)
+
+        # image becomes thumbnail based on webnail
+        nim.thumbnail((128, 128), Image.ANTIALIAS)
+        os.remove(thumbf)
+        nim.save(thumbf, img_type)
+
+    def render(self):
+        """ does execute the commands of the form data """
+        _ = self.request.getText
+        form = self.form
+        request = self.request
+        pagename = self.pagename
+
+        if not Image:
+            msg = _('The action %(action)s needs python imaging library (PIL) installed' % {'action': action_name})
+            request.theme.add_msg(msg, "error")
+            self.page.send_page()
+            return
+
+        request.formatter = Formatter(request)
+        attachment_path = AttachFile.getAttachDir(request, self.pagename)
+        command = request.form.get('do', ['none'])[0]
+
+        if command == 'VS':
+            web = {}
+            images = request.form.get('target', [''])[0]
+            images = images.split(',')
+            target = images[0]
+            images = (images[1:])
+
+            all_description = request.form.get('alias', [''])[0]
+            all_description = all_description.split('!,!')
+            #this_description = all_description[0]
+            all_description = (all_description[1:])
+
+            all_exif_date = request.form.get('exif_date', [''])[0]
+            all_exif_date = all_exif_date.split(',')
+            this_exif_date = all_exif_date[0]
+            all_exif_date = (all_exif_date[1:])
+
+           # XXX Check that all lists have same length
+            z = 0
+            for img in images:
+                if target == img:
+                    idx = z
+                z += 1
+            n = len(images)
+
+            attachment_path = AttachFile.getAttachDir(request, pagename)
+
+            static_path, static_url = self.get_path_url(request, pagename, attachment_path)
+
+            web['src'] = static_url+target #AttachFile.getAttachUrl(pagename, target, request)
+            web['title'] = target
+
+            image_link = request.formatter.image(**web)
+
+            request.theme.send_title(pagename,
+                                 pagename=pagename,
+                                 body_onload="arnica_preload();",
+                                 html_head=self.html_js(request, AttachFile.getAttachUrl(pagename, target, request), idx))
+
+            request.write(request.formatter.startContent("content"))
+            html = self.html_slideform(request, pagename, all_description, all_exif_date, images, idx)
+            request.write(html)
+            request.write(request.formatter.endContent())
+            request.write(request.theme.send_footer(pagename))
+            msg = None
+
+        elif command == 'PS':
+            msg = None
+
+        elif command == 'BS':
+            msg = "gone back" #None
+
+        elif request.user.may.delete(pagename):
+        # only users which are allowed to delete sould use this tools
+
+            target = request.form.get('target', [''])[0]
+            filename, ext = os.path.splitext(target)
+
+            if ext == '.gif'  or  ext == '.png':
+                img_type = 'PNG'
+                thumbfile = "tmp.thumbnail_%(file)s.png" % {"file": filename}
+                webnail = "tmp.webnail_%(file)s.png" % {"file": filename}
+            else:
+                img_type = "JPEG"
+                thumbfile = "tmp.thumbnail_%(file)s.jpg"  % {"file": filename}
+                webnail = "tmp.webnail_%(file)s.jpg"  % {"file": filename}
+
+            static_path, static_url = self.get_path_url(request, pagename, attachment_path)
+
+            thumbf = os.path.join(static_path, thumbfile)
+            webf = os.path.join(static_path, webnail)
+            infile = os.path.join(attachment_path, target)
+
+            msg = None
+            # removes (moves to bak)
+            if command == 'RM':
+                if os.path.exists(infile + '.bak'):
+                    os.unlink("%(file)s.bak" % {"file": infile})
+                filesys.rename(infile, "%(file)s.bak" % {"file": infile})
+                msg = _('%(target)s deleted, backup in place' % {
+                      'target':target})
+            # rotate left
+            elif command == 'RL':
+                self.image_rotate(infile, webf, thumbf, 90, img_type)
+                msg = _('%(target)s rotated to left 90 degrees' % {'target':target})
+
+            # rotate right
+            elif command == 'RR':
+                self.image_rotate(infile, webf, thumbf, 270, img_type)
+                msg = _('%(target)s rotated to right 90 degrees' % {'target':target})
+            else:
+                # fallback
+                msg = _('action not implemented: %s') % (command, )
+        else:
+            msg = _('Your are not allowed to change attachments on this page: %s') % (pagename,)
+
+        if msg:
+            request.theme.add_msg(msg, "info")
+            self.page.send_page()
+
+def execute(pagename, request):
+    """ Main dispatcher for the arnica_slides action.
+    """
+    return arnica_slides(request, pagename).render()
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/plugin/parser/text_x_arnica.py	Fri Mar 07 15:48:15 2008 +0100
@@ -0,0 +1,649 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - arnica parser 
+       
+    This parser is used to visualize a couple of images as a thumbnail gallery.
+    Optional a description of an image could be added including WikiName.
+    On default the image name and it's creation date is shown.
+    If you click on a thumbnail you get the webnails shown. By a menue you are able to toggle between the slides.
+
+    Syntax:
+      {{{
+      #!arnica [target_page=target_page]
+               [columns=columns],[filter=filter],[mode=mode],
+               [show_text=show_text],[show_date=show_date], [show_tools=show_tools],
+               [sort_by_name=sort_by_name],[sort_by_date=sort_by_date], [sort_by_alias=sort_by_alias],
+               [reverse_sort=reverse_sort],
+               [only_items=only_items],[template_itemlist=template_itemlist],
+               [album=album],[album_name=album_name],[front_image=front_image],
+               [thumbnail_width=thumbnail_width],[webnail_width=webnail_width],[text_width=text_width],
+               [image_for_webnail=image_for_webnail],
+               [sequence_name=sequence_name], [sequence_fps=sequence_fps],
+               [border_thick=border_thick],[renew=renew],[help=help]
+      * [[image1.jpg|alias]]
+      * [[image2.jpg|alias]]
+      }}}
+
+    KEYWORD PARAMETERS:
+        target_page:       page to read attachments
+        columns:           number of columns for thumbnails
+        filter:            regex to select images
+        show_text:         default is 1 description is shown
+                           any other means no description
+        show_date:         default is 1 date info from exif header if available is shown
+        show_tools:        default is 1 icon toolbar is show any other disables this
+        sort_by_name:      default is 1, the images are sorted by name, but not if only_items is 1
+        sort_by_date:      default is 0, if set to 1 the images are sorted to the modification time
+                           if they do have all the same time then the result is random
+        sort_by_alias      default is 0, if set to 1 and only_items set to 1 it is used to order the images by the alias name
+        reverse_sort:      default is 0, if set to 1 the file list is reversed
+                           any other means no description
+        mode:              default is 1 this means description below the image
+                           any other number means description right of image
+        only_items:        default is 0 if it is set to 1 only images which are described in listitem are shown
+                           dependend on the order of the items
+        template_itemlist: default is 0, if set to 1 an item list is shown which could be copied into the script. 
+        album:             default is 0 if set to 1 only the first image of a series is shown but slideshow over all images 
+        album_name:        useful for album. default is 'album' use it as short name for the album. 
+        front_image:       Useful for album.  default is ''. The first image is shown in front of the album and slideshow.
+                           If set to an existing image name this is shown in front of album and slideshow. 
+                           The slide show could start by this somewhere.
+        border_thick:      default is 1 this is the thickness in pixeln of the outer frame
+        renew:             default is 0 if set to 1 then all selected thumbnails_* and webnails_* removed.
+                           Afterwards they are new created.
+        thumbnail_width:   default is 128
+        webnail_width:     default is 640
+        text_width:        default is 140		   
+        image_for_webnail  default is 0 if set to 1 then the image is shown as preview and not the webnail
+        help:              default is 0 if set a copy of the CALLING SEQUENCE is shown, 
+                           (there are some new ideas around to show help to an user so this will be later replaced)
+                           
+
+    OPTIONAL INPUTS:
+        itemlist : if it is used and only_items is 1 then only the images in this list are ahown.
+                   The alias text is used as description of the image instead of the file name
+
+
+    
+    MODIFICATION HISTORY:
+    based on Gallery2 by ReimarBauer 2005-2008, ThomasWaldmann 2005, FlorianFesti 2006
+       
+    @copyright: 2008 by MoinMoin:ReimarBauer
+    @license: GNU GPL, see COPYING for details.
+"""
+Dependencies = ['time'] # do not cache
+
+import os, re, Image
+from random import randint
+from MoinMoin import wikiutil
+from MoinMoin.action import AttachFile
+from MoinMoin.Page import Page
+from MoinMoin.filter import EXIF
+
+class Parser:
+    extensions = '*.jpg'
+    def __init__(self, raw, request, **kw):
+        self.target_page = ''
+        self.sort_by_date = '0'
+        self.sort_by_name = '1'
+        self.sort_by_alias = '0'
+        self.album = '0'
+        self.album_name = 'album'
+        self.front_image = ''
+        self.template_itemlist = '0'
+        self.reverse_sort = '0'
+        self.border_thick = '1'
+        self.columns = '4'
+        self.filter = '.'
+        self.mode = '1'
+        self.help = '0'
+        self.show_text = '1'
+        self.show_date = '1'
+        self.show_tools = '1'
+        self.only_items = '0'
+        self.image_for_webnail = '0'
+        self.renew = '0'
+        self.thumbnail_width = '128'
+        self.webnail_width = '640'
+        self.text_width = '140'
+        self.form = None
+
+        test = kw.get('format_args', '')
+        if test:
+            for arg in kw.get('format_args', '').split(','):
+                if arg.find('=') > -1:
+                    key, value = arg.split('=')
+                    setattr(self, key, wikiutil.escape(value.strip(), quote=1))
+
+        self.width = str(int(self.thumbnail_width) + int(self.text_width))
+
+        self.raw = raw
+        self.request = request
+        self.form = request.form
+        self._ = request.getText
+
+        self.outer_table_style = ' border="%s"' % self.border_thick
+        self.inner_table_style = ' style="border-style:none; margin:10px;"'
+        self.td_style = ' align="center" style="padding:0; margin:2px 2px; border-style:none"'
+
+    def show_tools_restricted(self, this_target):
+        """ show only tools to users with enough rights 
+        @param this_target: image
+        """
+        if not self.request.user.may.delete(self.pagename):
+            return ''
+
+        return '''
+        <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
+          <td%(style)s>
+            <input type="hidden" name="action" value="arnica_slides">
+            <input type="hidden" name="do" value="RL">
+            <input type="hidden" name="target" value="%(this_target)s">
+            <input type="image" value="submit" src="%(htdocs)s/common/arnica/arnica_to_right.png" title="rotate to left">
+          </td>
+        </form>
+        <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
+          <td%(style)s>
+            <input type="hidden" name="action" value="arnica_slides">
+            <input type="hidden" name="do" value="RR">
+            <input type="hidden" name="target" value="%(this_target)s">
+            <input type="image"  value="submit" src="%(htdocs)s/common/arnica/arnica_to_left.png" title="rotate to right" >
+          </td>
+        </form>
+        <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
+          <td%(style)s>
+            <input type="hidden" name="action" value="arnica_slides">
+            <input type="hidden" name="do" value="RM">
+            <input type="hidden" name="target" value="%(this_target)s">
+            <input type="image" value="submit" src="%(htdocs)s/common/arnica/arnica_to_bak.png" title="move to bak" >
+           </td>
+        </form>''' % {
+            'baseurl': self.request.getBaseURL(),
+            'style': self.td_style,
+            'htdocs': self.request.cfg.url_prefix_static,
+            "pagename": self.quoted_pagename,
+            "this_target": this_target}
+
+    def tools_html(self, idx):
+        """ html code of thumbnails view with contol
+        @param idx: index postion of corresponding data
+        """
+        this_image = self.full[idx]
+
+        text = '''
+            <table align="center" width="%(thumbnail_width)s"%(tablestyle)s>
+                <tr>
+                    <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
+                        <td%(style)s>
+                            <input type="hidden" name="action" value="AttachFile">
+                            <input type="hidden" name="do" value="get">
+                            <input type="hidden" name="target" value='%(this_target)s'>
+                            <input type="image" value="submit" src="%(htdocs)s/common/arnica/arnica_to_full.png" title="load image">
+                        </td>
+                    </form>
+                    <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
+                        <td%(style)s>
+                            <input type="hidden" name="action" value="arnica_slides">
+                            <input type="hidden" name="do" value="VS">
+                            <input type="hidden" name="alias" value='%(description)s'>
+                            <input type="hidden" name="target" value='%(target)s'>
+                            <input type="hidden" name="exif_date" value='%(exif_date)s'>
+                            <input type="image" value="submit" src="%(htdocs)s/common/arnica/arnica_to_slide.png" title="slide_show" >
+                       </td>
+                    </form>
+                    %(show_tools_restricted)s
+                </tr>
+            </table>'''   % {
+            "baseurl": self.request.getScriptname(),
+            "pagename": self.quoted_pagename,
+            "htdocs": self.request.cfg.url_prefix_static,
+            "tablestyle": self.inner_table_style,
+            "style": self.td_style,
+            "thumbnail_width": self.thumbnail_width,
+            "description": self.description[idx] + '!,!' + '!,!'.join(self.description),
+            "exif_date": self.exif_date[idx] + ',' + ','.join(self.exif_date),
+            "target": self.webimg[idx] + ',' + ','.join(self.webimg),
+            "this_target": self.full[idx],
+            "thumbnail": "%s%s" % (self.static_url, self.thumb[idx]),
+            "show_tools_restricted":self.show_tools_restricted(this_image)
+            }
+
+        return text
+
+    def show_alias_mode2(self, idx):
+        """ view mode 2 alias text is on righthand of image """
+        if self.show_text == '1':
+            return '''
+<td valign="top" width="%(text_width)s" %(style)s>
+ %(this_alias)s
+</td>''' % {
+        "this_alias": self.description[idx],
+        "text_width": self.text_width,
+        "style": ' align="left" style="padding:0px; margin:2px 2px; border-style:none"'}
+        else:
+            return ''
+
+    def show_date_mode2(self, idx):
+        """ view mode 2 selection for date """
+        if self.show_date == '1':
+            return '''<td%(style)s><p>%(this_exif_date)s</p></td>''' % {
+                      "style": self.td_style,
+                      "this_exif_date": self.exif_date[idx]}
+        else:
+            return ''
+
+    def show_tools_mode2(self, idx):
+        """ view mode 2 selection for tools """
+        if self.show_tools == '1':
+            return "<td align=""center""%(style)s> %(tools)s </td>" % {
+                "style": self.td_style,
+                "tools": self.tools_html(idx)}
+        else:
+            return ''
+
+    def mode2_html(self, idx):
+        """ html code of mode 2 """
+        text = '''
+        <tr valign="center">
+        <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
+            <td align="center" valign="center" width="%(thumbnail_width)s"
+            %(tdstyle)s>
+                <input type="hidden" name="action" value="arnica_slides">
+                <input type="hidden" name="do" value="VS">
+                <input type="hidden" name="alias" value='%(description)s'>
+                <input type="hidden" name="exif_date" value='%(exif_date)s'>
+                <input type="hidden" name="target" value='%(target)s'>
+                <input type="image" value="submit" src="%(thumbnail)s">
+            </td>
+        </form>
+            %(alias_html)s 
+    </tr>
+    <tr>%(tools_html)s%(date_html)s</tr>''' % {
+     "tdstyle": self.td_style,
+     "baseurl": self.request.getScriptname(),
+     "pagename": self.quoted_pagename,
+     "thumbnail_width": self.thumbnail_width,
+     "description": self.description[idx] + '!,!' + '!,!'.join(self.description),
+     "exif_date": self.exif_date[idx] + ',' + ','.join(self.exif_date),
+     "target": self.webimg[idx] + ',' + ','.join(self.webimg),
+     "thumbnail": "%s%s" % (self.static_url, self.thumb[idx]),
+     "tools_html": self.show_tools_mode2(idx),
+     "date_html": self.show_date_mode2(idx),
+     "alias_html": self.show_alias_mode2(idx)
+     }
+
+        return text
+
+    def show_tools_mode1(self, idx):
+        """ view mode 1 selection of tools """
+        if self.show_tools == '1':
+            text = "<tr><td align=""center""%(style)s>%(tools)s </td></tr>" % {
+                "style":self.td_style,
+                "tools":self.tools_html(idx)}
+        else:
+            text = ''
+        return text
+
+    def show_date_mode1(self, idx):
+        """ view mode 1 selection of date """
+        if self.show_date == '1':
+            return '''
+<tr>
+<td%(style)s>%(this_exif_date)s</td>
+</tr>''' % {
+        "style":self.td_style,
+        "this_exif_date": self.exif_date[idx]}
+        else:
+            return ''
+
+    def show_alias_mode1(self, idx):
+        """ view mode 1 alias text below image """
+        if self.show_text == '1':
+            return '''
+<tr>
+<td width="%(thumbnail_width)s" %(style)s> %(this_alias)s</td>
+</tr>''' % {
+        "thumbnail_width": self.thumbnail_width,
+        "style": ' align="left" style="padding:0em; margin:2px 2px; border-style:none"',
+        "this_alias": self.to_wikitext(self.description[idx])}
+        else:
+            return ''
+
+    def mode1_html(self, idx):
+        """ html code of mode 1 (default)"""
+        text = '''
+    <table width="%(thumbnail_width)s" align="center" valign="center"%(style)s>
+    <TR align="center" valign="center">
+        <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
+            <td align="center" valign="middle" width="%(thumbnail_width)s"
+            %(tdstyle)s>
+                <input type="hidden" name="action" value="arnica_slides">
+                <input type="hidden" name="do" value="VS">
+                <input type="hidden" name="alias" value='%(description)s'>
+                <input type="hidden" name="exif_date" value='%(exif_date)s'>
+                <input type="hidden" name="target" value='%(target)s'>
+                <input type="image" value="submit" src="%(thumbnail)s" >
+            </td>
+        </form>
+    </TR>
+      %(alias_html)s
+      %(date_html)s
+      %(tools_html)s
+</table>'''% {
+     "tdstyle": self.td_style,
+     "style": self.inner_table_style,
+     "baseurl": self.request.getScriptname(),
+     "pagename": self.quoted_pagename,
+     "description": self.description[idx] + '!,!' + '!,!'.join(self.description),
+     "exif_date": self.exif_date[idx] + ',' + ','.join(self.exif_date),
+     "target": self.webimg[idx] + ',' + ','.join(self.webimg),
+     "thumbnail": "%s%s" % (self.static_url, self.thumb[idx]),
+     "thumbnail_width": self.thumbnail_width,
+     "tools_html": self.show_tools_mode1(idx),
+     "date_html": self.show_date_mode1(idx),
+     "alias_html": self.show_alias_mode1(idx)
+     }
+
+        return text
+
+    def get_files(self, path, files, quotes):
+        """ get files creates lists for thumbnails and webnails 
+        @param path: path to attachment
+        @param files: file names of images
+        @param quotes: text alias for image file
+        """
+        self.web = []
+        self.full = []
+        self.thumb = []
+        self.exif_date = []
+        self.imgtype = []
+        self.description = []
+
+        ddict = {}
+        n = len(quotes['image'])
+        if n > 0:
+            i = 0
+            for txt in quotes['image']:
+                ddict[txt] = quotes['alias'][i]
+                i += 1
+
+        self.source_type = ''
+        for attfile in files:
+            # only files not thumb or webnails
+            if not attfile.startswith('tmp.'):
+                # only images
+                if wikiutil.isPicture(attfile):
+                    self.description.append(ddict.get(attfile, attfile))
+                    self.full.append(attfile)
+
+                    fname, ext = os.path.splitext(attfile)
+                    if ext in ('.gif', '.png'):
+                        self.imgtype.append('PNG')
+                        webnail = 'tmp.webnail_%s.png' % fname
+                        thumbfile = 'tmp.thumbnail_%s.png' % fname
+                    else:
+                        self.imgtype.append("JPEG")
+                        webnail = 'tmp.webnail_%s.jpg' % fname
+                        thumbfile = 'tmp.thumbnail_%s.jpg' % fname
+
+                    infile = os.path.join(path, attfile)
+                    if os.path.exists(infile):
+                        self.web.append(webnail)
+                        self.thumb.append(thumbfile)
+
+                    f = open(infile, 'rb')
+                    tags = EXIF.process_file(f, 'DateTimeOriginal')
+                    f.close()
+                    if tags.has_key('EXIF DateTimeOriginal'):
+                        date = str(tags['EXIF DateTimeOriginal'])
+                        date = date.replace(':', '-', 2)
+                    else:
+                        date = '--'
+
+                    self.exif_date.append(wikiutil.escape(date, quote=1))
+
+    def to_wikitext(self, text):
+        """
+        converts text to wiki name if it is written as WikiName or [[wikiname]]
+        @param text: text to parse and render
+        """
+        text = ''.join(text)
+        text = text.replace('\\n', '\n')
+        from MoinMoin.parser.text_moin_wiki import Parser
+        return wikiutil.renderText(self.request, Parser, text, line_anchors=False)
+
+    def get_quotes(self):
+        """  get's the qoutes from the itemlist  """
+        quotes = self.raw.split('\n')
+        quotes = [quote.strip() for quote in quotes]
+        quotes = [quote[2:] for quote in quotes if quote.startswith('* ')]
+
+        image = []
+        text = []
+
+        for line in quotes:
+            img, alias = line[2:-2].split('|', 1)
+            alias = alias.strip()
+            alias = wikiutil.escape(alias, quote=1)
+            text.append(alias)
+            image.append(img.strip())
+
+        return {
+            'alias': text,
+            'image': image,
+        }
+
+    def print_help(self):
+        self.request.write('''
+<br>
+{{{<br>
+#!arnica   [targe_page=targe_page], <br>
+           [columns=columns],[filter=filter],[mode=mode],<br>
+           [show_text=show_text],[show_date=show_date], [show_tools=show_tools],<br>
+           [sort_by_name=sort_by_name],[sort_by_date=sort_by_date],[sort_by_alias=sort_by_alias]<br>
+           [reverse_sort=reverse_sort],<br>
+           [only_items=only_items],[template_itemlist=template_itemlist],<br>
+           [album=album],[album_name=album_name],[front_image=front_image],<br>
+           [thumbnail_width=thumbnail_width],[webnail_width=webnail_width],[text_width=text_width],<br>
+           [image_for_webnail=image_for_webnail],<br>
+           [border_thick=border_thick],[renew=renew],[help=help]<br>
+ * [image1.jpg alias] <br>
+ * [image2.jpg alias] <br>
+}}}''')
+
+    def format(self, formatter):
+        """ does the format """
+        _ = self._
+
+        if self.help == '1':
+            self.print_help()
+            return
+
+        ImageDict = {}
+        quotes = self.get_quotes()
+        current_pagename = formatter.page.page_name
+
+        if self.target_page and (not self.request.user.may.read(self.target_page) or not Page(self.request, self.target_page).exists()):
+            self.request.write(_("Page %(pagename)s does not exists or you don't have enough rights." % {"pagename": self.target_page}))
+            return
+
+        if self.target_page:
+            current_pagename = self.target_page
+        self.pagename = current_pagename
+
+        self.quoted_pagename = wikiutil.quoteWikinameURL(self.pagename)
+        attachment_path = AttachFile.getAttachDir(self.request, current_pagename, create=1)
+
+        self.static_path = attachment_path
+        self.static_url = AttachFile.getAttachUrl(self.pagename, '', self.request)
+
+        if self.only_items == '1':
+            all_files = quotes['image']
+            result = []
+            for attfile in all_files:
+                infile = os.path.join(attachment_path, attfile)
+                if os.path.exists(infile):
+                    result.append(attfile)
+            all_files = result
+
+            if self.sort_by_alias == '1':
+                new_ordered_files = []
+                alias_text = quotes['alias']
+
+                i = 0
+                for attfile in all_files:
+                    infile = os.path.join(attachment_path, attfile)
+                    ImageDict[alias_text[i]] = attfile
+                    i += 1
+
+                keys = ImageDict.keys()
+                keys.sort()
+                for txt in keys:
+                    new_ordered_files.append(ImageDict[txt])
+
+                all_files = new_ordered_files
+                ImageDict.clear()
+        else:
+            all_files = os.listdir(attachment_path)
+
+        if self.filter != '.':
+            result = []
+            for test in all_files:
+                if re.match(self.filter, test):
+                    result.append(test)
+            all_files = result
+
+        if not all_files:
+            self.request.write("<br><br><h1>No matching image file found!</h1>")
+            return
+
+        if self.sort_by_name == '1' and self.only_items == '0':
+            all_files.sort()
+
+        if self.sort_by_date == '1':
+            for attfile in all_files:
+                infile = os.path.join(attachment_path, attfile)
+                ft_file = "%s%s" % (str(os.path.getmtime(infile)), str(randint(0, 65535)))
+                ImageDict[ft_file] = attfile
+
+            keys = ImageDict.keys()
+            keys.sort()
+            file_mdate = []
+            for txt in keys:
+                file_mdate.append(ImageDict[txt])
+            all_files = file_mdate
+            ImageDict.clear()
+
+        if self.reverse_sort == '1':
+            all_files.reverse()
+
+        self.get_files(attachment_path, all_files, quotes)
+
+        if self.template_itemlist == '1':
+            self.request.write('Copy the following listitems into the script. Replace alias with the label you want. Afterwards disable template_itemlist by setting it to 0:<BR>')
+            for attfile in self.full:
+                self.request.write(' * [[%(attfile)s|%(alias)s]]<br>\n' % {
+                                   'attfile': attfile,
+                                   'alias': 'alias'
+                                    })
+
+        i = 0
+        z = 1
+        cols = int(self.columns)
+
+        n = len(self.full)
+        if  self.album == '0':
+            self.request.write("<table%s>" % self.outer_table_style)
+            if self.mode == '1' or cols > 1:
+                self.request.write('<tr valign="top">')
+                self.request.write('<td%s>' % self.td_style)
+
+
+        if self.album == '1':
+            front_image = self.front_image
+            if self.front_image == '':
+                front_image = self.full[0]
+
+            ii = 0
+            for tst in self.full:
+                if tst == front_image:
+                    break
+                ii += 1
+
+        for attfile in self.full:
+            if self.album == '1':
+                if tst == front_image:
+                    i = ii
+
+            this_webnail = self.web[i]
+            this_imgtype = self.imgtype[i]
+            this_thumbfile = self.thumb[i]
+
+            thumbf = os.path.join(self.static_path, this_thumbfile)
+            webf = os.path.join(self.static_path, this_webnail)
+
+            if self.renew == '1':
+                if os.path.exists(thumbf):
+                    os.unlink(thumbf)
+                if os.path.exists(webf):
+                    os.unlink(webf)
+
+            if not os.path.exists(webf) or not os.path.exists(thumbf):
+                infile = os.path.join(attachment_path, attfile)
+                im = Image.open(infile)
+
+                if not os.path.exists(webf):
+                    im.thumbnail((int(self.webnail_width), int(self.webnail_width)), Image.ANTIALIAS)
+                    if self.image_for_webnail == '1':
+                        os.link(os.path.join(attachment_path, attfile), webf)
+                    else:
+                        im.save(webf, this_imgtype)
+                if not os.path.exists(thumbf):
+                    im.thumbnail(((int(self.thumbnail_width)), ((int(self.thumbnail_width)))),
+                                   Image.ANTIALIAS)
+                    im.save(thumbf, this_imgtype)
+
+            if self.image_for_webnail == '1':
+                self.webimg = self.full
+            else:
+                self.webimg = self.web
+
+            if self.mode == '1':
+                text = self.mode1_html(i)
+                self.request.write(''.join(text))
+
+            if self.mode == '2':
+                text = self.mode2_html(i)
+                if cols > 1: self.request.write('<table valign="bottom">')
+                self.request.write(''.join(text))
+                if cols > 1: self.request.write('</table>')
+
+            if self.mode == '1' or cols > 1:
+                if self.album == '0':
+                    if  z < cols:
+                        self.request.write('</td>')
+                        if z < n and  i < n - 1:
+                            self.request.write('<td%s>' % self.td_style)
+                        if i == n - 1:
+                            self.request.write('</tr>')
+                    else:
+                        self.request.write('</td>')
+                        self.request.write('</tr>')
+                        if i < n - 1:
+                            self.request.write('<tr valign="top">')
+                            self.request.write('<td%s>' % self.td_style)
+            i += 1
+            z += 1
+            if z > cols:
+                z = 1
+
+            if self.album == '1':
+                self.request.write("%(n)s images (%(album_name)s)" % {"n": str(n), "album_name": self.album_name})
+                break
+
+        if self.album == '0':
+            if i < n:
+                self.request.write('</td>')
+                self.request.write('</tr>')
+            self.request.write('</table>')
+
Binary file htdocs/common/arnica/arnica_back.png has changed
Binary file htdocs/common/arnica/arnica_disabled.png has changed
Binary file htdocs/common/arnica/arnica_first.png has changed
Binary file htdocs/common/arnica/arnica_first_disabled.png has changed
Binary file htdocs/common/arnica/arnica_last.png has changed
Binary file htdocs/common/arnica/arnica_last_disabled.png has changed
Binary file htdocs/common/arnica/arnica_next.png has changed
Binary file htdocs/common/arnica/arnica_next_disabled.png has changed
Binary file htdocs/common/arnica/arnica_previous.png has changed
Binary file htdocs/common/arnica/arnica_to_bak.png has changed
Binary file htdocs/common/arnica/arnica_to_full.png has changed
Binary file htdocs/common/arnica/arnica_to_left.png has changed
Binary file htdocs/common/arnica/arnica_to_right.png has changed
Binary file htdocs/common/arnica/arnica_to_slide.png has changed