view data/plugin/parser/text_x_arnica.py @ 334:ff4d2f96a36b

text_x_arnica: applied patch for new parameter album_link_page link to page instead of slideshow by Johannes Berg
author Reimar Bauer <rb.proj AT googlemail DOT com>
date Tue, 20 Jan 2009 19:28:59 +0100
parents a82e059e4477
children a6d96bdc0598
line wrap: on
line source
# -*- coding: iso-8859-1 -*-
"""
    MoinMoin - arnica parser

    This parser is used to visualize a couple of images as a thumbnail gallery.
    Optionally, a description of an image can be added.

    By default the image name and its creation date is shown.
    If you click on a thumbnail you get navigation tools shown to slide through your images.

    Based on Gallery2 by ReimarBauer 2005-2008, ThomasWaldmann 2005, FlorianFesti 2006

    @copyright: 2008 by MoinMoin:ReimarBauer
    @license: GNU GPL, see COPYING for details.
"""

import os, re
from random import randint
from MoinMoin import wikiutil
from MoinMoin.action import AttachFile
from MoinMoin.packages import packLine
from MoinMoin.Page import Page

parser_name = __name__.split('.')[-1]


def arnica_settings(target_page=u'', columns=4, file_regex=u'.',
                    image_for_webnail=False,
                    show_text=True, show_date=True, show_tools=False, show_title=True,
                    sort_by=("name", "date", "alias"),
                    reverse_sort=False,
                    only_items=False, template_itemlist=False,
                    album=False, album_title=unicode, album_image=u'', album_link_page=False,
                    renew=False,
                    thumbnail_width=128,
                    webnail_width=640):
    """ dummy function to initialize all default parameters for arnica. The parameters are checked for wrong input.
    @param target_page: page to read attachments from. empty pagename is current page.
    @param columns: number of columns for thumbnails, default is 4. 0 means no linebreak
    @param file_regex: regex for selecting images
    @param image_for_webnail if set then the image is shown instead of the webnail
    @param show_text: default shows description
    @param show_title: show album title
    @param show_date: default shows date from exif header, if available
    @param show_tools: default does not show the icon toolbar
    @param sort_by: default, sorts images by name, optional by date or by alias
    @param reverse_sort: if set, the file list is sorted in reverse order
    @param only_items: if set, only images which are described in listitem are shown, e.g.
                       * [[image1.jpg|alias]]
                       * [[image2.jpg|alias]]
    @param template_itemlist: if set, an item list is shown which could be copied into the wiki page
    @param album: if set, selects album mode, only thumbnail from first image is shown, related is album title and album_image
    @param album_title: default is pagename of the images for the album.
    @param album_image: image to show on album default is the first image
    @param album_link_page: link to page instead of slideshow
    @param renew: if set then all selected thumbnails_* and webnails_* are removed and will be recreated
    @param thumbnail_width: default width of thumbnail is 128px
    @param webnail_width: default width of webnail is 640px
    """
    return locals()

def _get_files(request, pagename):
    """ get files dependent on isPicture and ignores tmp. files
    @param pagename: name of the page where to get attachments
    """
    # ToDo remove tmp. files check later
    files = AttachFile._get_files(request, pagename)
    files = [fn for fn in files if wikiutil.isPicture(fn) and not fn.startswith('tmp.')]
    return files

class Parser:
    """ arnica parser """

    extensions = ['.jpg', '.jpeg', '.gif', '.png']

    def __init__(self, raw, request, **kw):
        self.pagename = request.page.page_name
        self.raw = raw
        self.request = request
        self.formatter = request.formatter
        self.form = None
        self._ = request.getText

        args = kw.get('format_args', '')
        self.init_settings = False
        # we use a macro definition to initialize the default init parameters
        # if a user enters a wrong parameter the failure is shown by the exception
        try:
            settings = wikiutil.invoke_extension_function(request, arnica_settings, args)
            for key, value in settings.items():
                setattr(self, key, value)
            # saves the state of valid input
            self.init_settings = True
        except ValueError, err:
            # ToDo use formatter
            request.write(self.formatter.text(err))

        self.arnica_image = {} # self.arnica_image[image] = (webnail, thumbnail, exif_date, description, order)
        self.Image = wikiutil.importWikiPlugin(self.request.cfg, "macro", "Image", function="Image")

    def html_tools_restricted(self, this_target):
        """ shows restricted tools
            @param this_target: image
        """
        if self.album or not self.request.user.may.delete(self.pagename):
            return ''
        return """
<li class="tool">
    <form action="%(url)s" method="POST" enctype="multipart/form-data">
        <input type="hidden" name="action" value="arnica_slides">
        <input type="hidden" name="do" value="rotate_left">
        <input type="hidden" name="target" value="%(this_target)s">
        <input type="image" value="submit" src="%(htdocs)s/arnica/img/arnica_rotate_to_left.png" title="rotate to left">
    </form>
</li>
<li class="tool">
    <form action="%(url)s" method="POST" enctype="multipart/form-data">
        <input type="hidden" name="action" value="arnica_slides">
        <input type="hidden" name="do" value="rotate_right">
        <input type="hidden" name="target" value="%(this_target)s">
        <input type="image"  value="submit" src="%(htdocs)s/arnica/img/arnica_rotate_to_right.png" title="rotate to right">
    </form>
</li>
<li class="tool">
    <form action="%(url)s" method="POST" enctype="multipart/form-data">
         <input type="hidden" name="action" value="arnica_slides">
         <input type="hidden" name="do" value="delete">
         <input type="hidden" name="target" value="%(this_target)s">
         <input type="image" value="submit" src="%(htdocs)s/arnica/img/arnica_remove_image.png" title="move to bak">
    </form>
</li>""" % {
            'url': Page(self.request, self.pagename).url(self.request),
            'htdocs': self.request.cfg.url_prefix_static,
            "pagename": wikiutil.quoteWikinameURL(self.pagename),
            "this_target": this_target,
        }

    def html_tools(self, image):
        """ html code of thumbnails view with contol
        @param image: image as key for corresponding data
        """
        image_names = self.arnica_image.keys()
        index = [self.arnica_image[img][4] for img in image_names]
        selected_images = [image_names[int(idx)] for idx in index]

        html = """
<ul>
<li class="tool">
    <form action="%(url)s" method="POST" enctype="multipart/form-data">
        <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/arnica/img/arnica_full_image.png" title="load image">
    </form>
</li>
<li class="tool">
    <form action="%(url)s" method="POST" enctype="multipart/form-data">
        <input type="hidden" name="action" value="arnica_slides">
        <input type="hidden" name="do" value="slide_show">
        <input type="hidden" name="alias" value="%(description)s">
        <input type="hidden" name="target" value="%(target)s">
        <input type="hidden" name="pagename" value="%(pagename)s">
        <input type="hidden" name="images" value="%(images)s">
        <input type="hidden" name="original_images" value="%(original_images)s">
        <input type="hidden" name="exif_date" value="%(exif_date)s">
        <input type="image" value="submit" title="slide show" src="%(htdocs)s/arnica/img/arnica_load_slide_show.png">
    </form>
</li>
%(html_tools_restricted)s
</ul>
""" % {
        "url": Page(self.request, self.pagename).url(self.request),
        "pagename": self.pagename,
        "htdocs": self.request.cfg.url_prefix_static,
        "description": packLine([(self.arnica_image[image][3]).replace('"', '&quot;')] + [(self.arnica_image[img][3]).replace('"', '&quot;') for img in selected_images]),
        "exif_date": packLine([self.arnica_image[image][2]] + [self.arnica_image[img][2] for img in selected_images]),
        "target": self.arnica_image[image][0],
        "original_images": packLine([image] + selected_images),
        "images": packLine([self.arnica_image[image][0]] + [self.arnica_image[img][0] for img in selected_images]),
        "original_images": packLine([image] + selected_images),
        "this_target": image,
        "html_tools_restricted": self.html_tools_restricted(image),
        }
        return html

    def html_show_tools(self, image):
        """ shows toolbox
        @param image: image as key for corresponding data
        """
        html = ''
        if self.show_tools:
            html = '<div class="html-show-tools">%(tools)s</div>' % {
                "tools": self.html_tools(image)}
        return html

    def html_show_date(self, image):
        """ shows date
        @param image: image as key for corresponding data
        """

        html = ''
        if self.show_date:
            html = '<div class="show-datetime">%(this_exif_date)s</div>' % {
                "this_exif_date": self.formatter.text(self.arnica_image[image][2])}
        return html

    def html_show_alias(self, image):
        """ alias text below image
        @param image: image as key for corresponding data
        """

        html = ''
        if self.show_text:
            html = '<div class="description"> %(this_alias)s</div>' % {
                    "this_alias": self.to_wikitext(wikiutil.make_breakable(self.arnica_image[image][3], self.thumbnail_width / 9))}
        return html

    def html_arrange_thumbnails(self, image, selected_images):
        """ defines arrangement of thumbnail, text, date and tools
        @param image: image as key for corresponding data
        @param selected_images: ordered list of selected images
        """
        title = ""
        if self.album and self.show_title:
            title = '<div class="title">%(n)d images (%(album_title)s)</div>' % {"n": len(self.arnica_image),
                                                        "album_title": self.album_title or self.pagename}
        html = """
<div class="thumbnail" style="width:%(width)spx">
    %(title)s
    <form action="%(url)s" method="POST" enctype="multipart/form-data">
      <div class="imagecont" style="height:%(width)spx;">
        <div class="image" style="width:%(width)spx;">
             <input type="hidden" name="action" value="%(action)s">
             <input type="hidden" name="do" value="slide_show">
             <input type="hidden" name="alias" value="%(description)s">
             <input type="hidden" name="target" value="%(target)s">
             <input type="hidden" name="pagename" value="%(pagename)s">
             <input type="hidden" name="images" value="%(images)s">
             <input type="hidden" name="original_images" value="%(original_images)s">
             <input type="hidden" name="exif_date" value="%(exif_date)s">
             <input type="image" value="submit" title="%(submit_title)s" src="%(thumbnail)s">
        </div>
      </div>
    </form>
    <div style="width:%(width)spx">
    %(html_tools)s
    %(alias_html)s
    %(date_html)s
    </div>
</div>
""" % {
        "title": title,
        "url": Page(self.request, self.pagename).url(self.request),
        "pagename": self.pagename,
        "description": packLine([(self.arnica_image[image][3]).replace('"', '&quot;')] + [(self.arnica_image[img][3]).replace('"', '&quot;') for img in selected_images]),
        "exif_date": packLine([self.arnica_image[image][2]] + [self.arnica_image[img][2] for img in selected_images]),
        "target": self.arnica_image[image][0],
        "original_images": packLine([image] + selected_images),
        "images": packLine([self.arnica_image[image][0]] + [self.arnica_image[img][0] for img in selected_images]),
        "thumbnail": self.arnica_image[image][1],
        "width": self.thumbnail_width,
        "html_tools": self.html_show_tools(image),
        "date_html": self.html_show_date(image),
        "alias_html": self.html_show_alias(image),
        "submit_title": { True: "images", False: "slide show" }[self.album_link_page],
        "action": { True: "show", False: "arnica_slides" }[self.album_link_page],
        }
        return html

    def define_thumb_webnails(self, files, image_alias):
        """ creates lists for thumbnails and webnails
        @param files: file names of images
        @param image_alias: text alias for image file
        """
        order = 0
        for attfile in files:
            description = attfile
            if image_alias.get(attfile):
                # use alias
                description = image_alias.get(attfile)[0]
            itemname = self.pagename + '/' + attfile
            img = self.Image(self.request, itemname)
            webnail = img.url(size=(self.webnail_width, self.webnail_width))
            thumbnail = img.url(size=(self.thumbnail_width, self.thumbnail_width))
            try:
                exif_date = self.request.user.getFormattedDateTime(img.ctime)
            except KeyError:
                exif_date = '--'
            self.arnica_image[attfile] = (webnail, thumbnail, exif_date, description, str(order))
            order += 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)
        from MoinMoin.parser.text_moin_wiki import Parser as WikiParser
        return wikiutil.renderText(self.request, WikiParser, text)

    def get_image_alias(self):
        """  gets the quotes from the item list and returns a dictionary of image and alias """
        # ToDo simplify
        quotes = self.raw.split('\n')
        quotes = [quote.strip() for quote in quotes]
        quotes = [quote[2:] for quote in quotes if quote.startswith('* ')]
        image_alias = {}
        counter = 0
        for line in quotes:
            if line.startswith('[[') and line.endswith(']]') and '|' in line:
                img, alias = line[2:-2].split('|', 1)
                # don't count an image more than once and verify that it is an image
                if wikiutil.isPicture(img.strip()) and img.strip() not in image_alias.keys():
                    image_alias[img.strip()] = (self.formatter.text(alias.strip()), counter, img)
                    counter += 1
        return image_alias

    def select_files(self, formatter):
        """ select files """
        # we need to take the page_name from the formatter.page otherwise
        # include does not work
        self.pagename = formatter.page.page_name
        if self.target_page and Page(self.request, self.target_page).exists() and self.request.user.may.read(self.target_page):
            self.pagename = self.target_page

        image_alias = self.get_image_alias()
        if self.only_items:
            # ToDo simplify
            # get the same order of files and aliastext as on the page written
            files = image_alias.keys()
            all_files = [fn for fn in files if wikiutil.isPicture(fn) and
                         AttachFile.exists(self.request, self.pagename, fn)]
        else:
            all_files = _get_files(self.request, self.pagename)
        if self.file_regex != u'.':
            all_files = [attfile for attfile in all_files if re.match(self.file_regex, attfile)]
        if all_files:
            self.define_thumb_webnails(all_files, image_alias)
        return all_files

    def render(self, formatter):
        """ renders thumbnails """
        _ = self._
        # checks if initializing of all attributes in __init__ was done
        if not self.init_settings:
            return
        if self.target_page and (not Page(self.request, self.target_page).exists() or not self.request.user.may.read(self.target_page)):
            text = _("""Page '%(new_pagename)s' does not exist or you don't have enough rights.""") % {"new_pagename": self.target_page}
            self.request.write(self.formatter.text(text))
            return
        if not self.arnica_image and not self.select_files(formatter):
            text = _("No matching image file found!")
            self.request.write(self.formatter.text(text))
            return
        if self.template_itemlist:
            self.request.write(self.formatter.div(1, css_class="text"))
            text = _("""\
Copy the following listitems into the script.
Replace alias with the label you want.
Afterwards disable template_itemlist by setting it to False:""")
            self.request.write(self.formatter.text(text))
            self.request.write(self.formatter.div(1))
            self.request.write(self.formatter.preformatted(1))
            keys = self.arnica_image.keys()
            keys.sort()
            for image in keys:
                text = ' * [[%s|alias]]\n' % image
                self.request.write(self.formatter.text(text))
            self.request.write(self.formatter.preformatted(0))
            self.request.write(self.formatter.div(0))
            self.request.write(self.formatter.div(0))

        col_count = 1
        cols = min([self.columns, len(self.arnica_image)])
        result = []
        image_names = self.arnica_image.keys()
        image_dict = {}
        if self.only_items:
            # ToDo simplify
            image_alias = self.get_image_alias()
            image_names = image_alias.keys()
            alias_text = image_alias.values()
            to_order = [int(alias_text[ix][1]) for ix in range(len(alias_text))]
            names = [(alias_text[ix][2]).strip() for ix in range(len(alias_text))]
            alias = [alias_text[ix][0] for ix in range(len(alias_text))]

            i = 0
            for ix in to_order:
                image_names[ix] = names[i]
                alias_text[ix] = alias[i]
                i += 1

            # sort by alias
            if self.sort_by == "alias":
                i = 0
                for img in image_names:
                    image_dict[alias_text[i]] = img
                    i += 1
                keys = image_dict.keys()
                keys.sort()
                image_names = [image_dict[txt] for txt in keys]
        else:
            # sort by date
            if self.sort_by == "date":
                for img in image_names:
                    itemname = self.pagename + '/' + img
                    # to get uniq times (gives order for sorting)
                    ft_file = "%d%x" % (self.Image(self.request, itemname).ctime, randint(0, 256))
                    image_dict[ft_file] =  img
                keys = image_dict.keys()
                keys.sort()
                image_names = [image_dict[txt] for txt in keys]

            # default sort by name
            elif self.sort_by == "name" and not self.only_items:
                image_names.sort()

        image_dict.clear()
        # reverse sort
        if self.reverse_sort:
            image_names.reverse()

        if self.album:
            cols = 1
            album_image = self.album_image or self.arnica_image.keys()[0] #self.high_resolution_image[0]
            if not album_image in self.arnica_image.keys():
                html = self.formatter.text(_("""You can't use as album image:
"%(album_image)s" because it does not exist or it is not listed
in your item list!""") % {"album_image": album_image, })
            else:
                html = self.html_arrange_thumbnails(album_image, image_names)
            result.append(''.join(html))
        else:
            for image in image_names:
                html = self.html_arrange_thumbnails(image, image_names)
                result.append(''.join(html))
                if col_count == cols and self.columns != 0:
                    col_count = 0
                    result.append('<br class="clearboth">')
                col_count += 1

        result.append('<br class="clearboth">')
        result.insert(0, self.formatter.div(1, css_class="arnica"))
        result.append(self.formatter.div(0))
        return ''.join(result)

    def format(self, formatter):
        """ parser output """
        # checks if initializing of all attributes in __init__ was done
        if self.init_settings:
            self.request.write(self.render(formatter))