Annotation of ExtFile/ExtImage.py, revision 1.1
1.1 ! dwinter 1: """ExtImage product module."""
! 2: ###############################################################################
! 3: #
! 4: # Copyright (c) 2001 Gregor Heine <mac.gregor@gmx.de>. All rights reserved.
! 5: # ExtFile Home: http://www.zope.org/Members/MacGregor/ExtFile/index_html
! 6: #
! 7: # Redistribution and use in source and binary forms, with or without
! 8: # modification, are permitted provided that the following conditions
! 9: # are met:
! 10: #
! 11: # 1. Redistributions of source code must retain the above copyright
! 12: # notice, this list of conditions and the following disclaimer.
! 13: # 2. Redistributions in binary form must reproduce the above copyright
! 14: # notice, this list of conditions and the following disclaimer in the
! 15: # documentation and/or other materials provided with the distribution.
! 16: # 3. The name of the author may not be used to endorse or promote products
! 17: # derived from this software without specific prior written permission
! 18: #
! 19: # Disclaimer
! 20: #
! 21: # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 22: # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 23: # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 24: # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 25: # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 26: # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 27: # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 28: # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 29: # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 30: # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 31: #
! 32: # In accordance with the license provided for by the software upon
! 33: # which some of the source code has been derived or used, the following
! 34: # acknowledgement is hereby provided :
! 35: #
! 36: # "This product includes software developed by Digital Creations
! 37: # for use in the Z Object Publishing Environment
! 38: # (http://www.zope.org/)."
! 39: #
! 40: ###############################################################################
! 41:
! 42: __doc__ = """ExtImage product module.
! 43: The ExtImage-Product works like the Zope Image-product, but stores the
! 44: uploaded image externally in a repository-direcory. It creates a preview
! 45: of the image (requires PIL)."""
! 46:
! 47: __version__='1.5.4'
! 48:
! 49: import Globals
! 50: from Products.ExtFile.ExtFile import *
! 51: from Globals import HTMLFile, MessageDialog, InitializeClass
! 52: from AccessControl import ClassSecurityInfo
! 53: from webdav.Lockable import ResourceLockedError
! 54: import urllib, os, string, types
! 55: from os.path import join, isfile
! 56: from tempfile import TemporaryFile
! 57:
! 58: from webdav.WriteLockInterface import WriteLockInterface
! 59: from IExtFile import IExtImage
! 60:
! 61: from zLOG import *
! 62: _SUBSYS = 'ExtImage'
! 63: _debug = 0
! 64:
! 65: try: from zExceptions import Redirect
! 66: except ImportError: Redirect = 'Redirect'
! 67:
! 68: from Config import REPOSITORY_UMASK
! 69:
! 70: NO_PREVIEW = 0
! 71: GENERATE = 1
! 72: UPLOAD_NORESIZE = 2
! 73: UPLOAD_RESIZE = 3
! 74:
! 75: manage_addExtImageForm = HTMLFile('dtml/extImageAdd', globals())
! 76:
! 77:
! 78: def manage_addExtImage(self, id='', title='', descr='', file='', preview='',
! 79: content_type='', create_prev=0, maxx='', maxy='',
! 80: ratio=0, permission_check=0, redirect_default_view=0, REQUEST=None):
! 81: """ Add an ExtImage to a folder. """
! 82: if not id and getattr(file, 'filename', None) is not None:
! 83: # generate id from filename and make sure, it has no 'bad' chars
! 84: id = file.filename
! 85: id = id[max(string.rfind(id,'/'),
! 86: string.rfind(id,'\\'),
! 87: string.rfind(id,':'))+1:]
! 88: title = title or id
! 89: id = normalize_id(id)
! 90: tempExtImage = ExtImage(id, title, descr, permission_check, redirect_default_view)
! 91: self._setObject(id, tempExtImage)
! 92: if file != '':
! 93: self._getOb(id).manage_file_upload(file, content_type, 0, create_prev, maxx, maxy, ratio)
! 94: if create_prev==UPLOAD_NORESIZE or create_prev==UPLOAD_RESIZE:
! 95: self._getOb(id).manage_file_upload(preview, content_type, 1, create_prev, maxx, maxy, ratio)
! 96: if REQUEST is not None:
! 97: return self.manage_main(self, REQUEST, update_menu=0)
! 98: return id
! 99:
! 100:
! 101:
! 102: class ExtImage(ExtFile):
! 103: """ The ExtImage-Product works like the Zope Image-product, but stores the
! 104: uploaded image externally in a repository-direcory. It can create a
! 105: preview of the image (requires PIL)."""
! 106:
! 107: __implements__ = (IExtImage, WriteLockInterface)
! 108:
! 109: security = ClassSecurityInfo()
! 110:
! 111: # what do people think they're adding?
! 112: meta_type = 'ExtImage'
! 113:
! 114: # default,min,max-sizes for the preview image
! 115: _image_size={'default':256,'min':1,'max':999}
! 116:
! 117: # store maxx and maxy
! 118: prev_maxx = _image_size['default']
! 119: prev_maxy = _image_size['default']
! 120:
! 121: ################################
! 122: # Init method #
! 123: ################################
! 124:
! 125: def __init__(self, id, title='', descr='', permission_check=0, redirect_default_view=0):
! 126: """ Initialize a new instance of ExtImage """
! 127: ExtImage.inheritedAttribute("__init__")(self, id, title, descr, permission_check, redirect_default_view)
! 128: self.prev_filename = []
! 129: self.prev_content_type = ''
! 130: self.prev_ratio = 1
! 131: self.has_preview = 0
! 132:
! 133: ################################
! 134: # Public methods #
! 135: ################################
! 136:
! 137: def __str__(self):
! 138: return self.tag()
! 139:
! 140: security.declareProtected(ViewPermission, 'tag')
! 141: def tag(self, preview=0, icon=0, height=None, width=None, alt=None,
! 142: scale=0, xscale=0, yscale=0, border='0', REQUEST=None, **args):
! 143: """ Generate an HTML IMG tag for this image, with customization.
! 144: Arguments to self.tag() can be any valid attributes of an IMG tag.
! 145: 'src' will always be an absolute pathname, to prevent redundant
! 146: downloading of images. Defaults are applied intelligently for
! 147: 'height', 'width', and 'alt'. If specified, the 'scale', 'xscale',
! 148: and 'yscale' keyword arguments will be used to automatically adjust
! 149: the output height and width values of the image tag.
! 150: Adopted and adapted from OFS/Image.py
! 151: """
! 152: if not self.is_webviewable():
! 153: preview = 1
! 154: if not self._access_permitted():
! 155: preview = 1
! 156: if preview and not self.has_preview:
! 157: icon = 1
! 158: if icon:
! 159: url = self._static_url(icon=1)
! 160: img_width, img_height = (32, 32)
! 161: elif preview:
! 162: url = self._static_url(preview=1)
! 163: img_width, img_height = self._getImageSize(self.prev_filename)
! 164: else:
! 165: url = self._static_url()
! 166: img_width, img_height = self._getImageSize(self.filename)
! 167: height = height or img_height
! 168: width = width or img_width
! 169:
! 170: # Auto-scaling support
! 171: xdelta = xscale or scale
! 172: ydelta = yscale or scale
! 173: if xdelta and width != None:
! 174: width = str(int(width) * xdelta)
! 175: if ydelta and height != None:
! 176: height = str(int(height) * ydelta)
! 177:
! 178: if alt is None: alt = self.title or ''
! 179: strg = '<img src="%s" border="%s" alt="%s"' % \
! 180: (url, border, alt)
! 181: if height: strg = '%s height="%s"' % (strg, height)
! 182: if width: strg = '%s width="%s"' % (strg, width)
! 183: for key in args.keys():
! 184: value = args.get(key)
! 185: strg = '%s %s="%s"' % (strg, key, value)
! 186: strg="%s />" % (strg)
! 187: return strg
! 188:
! 189: security.declareProtected(ViewPermission, 'preview')
! 190: def preview(self):
! 191: """ Return a preview of the image """
! 192: raise Redirect, self._static_url(preview=1)
! 193:
! 194: security.declareProtected(ViewPermission, 'preview_tag')
! 195: def preview_tag(self):
! 196: """ Generates the HTML IMG tag for the preview image """
! 197: return self.tag(preview=1)
! 198:
! 199: security.declareProtected(ViewPermission, 'preview_html')
! 200: def preview_html(self):
! 201: """ Same as preview_tag """
! 202: return self.preview_tag()
! 203:
! 204: security.declareProtected(ViewPermission, 'is_broken')
! 205: def is_broken(self):
! 206: """ Check if external file exists and return true (1) or false (0) """
! 207: if self.has_preview and self.filename != self.prev_filename:
! 208: if not self._get_fsname(self.prev_filename):
! 209: return 1
! 210: return ExtImage.inheritedAttribute("is_broken")(self)
! 211:
! 212: security.declareProtected(ViewPermission, 'is_webviewable')
! 213: def is_webviewable(self):
! 214: """ Return 1 for GIF, JPEG, and PNG images, otherwise return 0 """
! 215: format = self.format()
! 216: if format=='JPEG' or format=='GIF' or format=='PNG':
! 217: return 1
! 218: else:
! 219: return 0
! 220:
! 221: security.declareProtected(ViewPermission, 'get_prev_size')
! 222: def get_prev_size(self):
! 223: """ Returns the size of the preview file """
! 224: fn = self._get_fsname(self.prev_filename)
! 225: if fn:
! 226: return os.stat(fn)[6]
! 227: return 0
! 228:
! 229: security.declareProtected(ViewPermission, 'prev_rawsize')
! 230: def prev_rawsize(self):
! 231: """ Same as get_prev_size """
! 232: return self.get_prev_size()
! 233:
! 234: security.declareProtected(ViewPermission, 'prev_size')
! 235: def prev_size(self):
! 236: """ Returns a formatted stringified version of the preview size """
! 237: return self._bytetostring(self.get_prev_size())
! 238:
! 239: security.declareProtected(ViewPermission, 'width')
! 240: def width(self):
! 241: """ Pixel width of the image """
! 242: return self._getImageSize(self.filename)[0]
! 243:
! 244: security.declareProtected(ViewPermission, 'height')
! 245: def height(self):
! 246: """ Pixel height of the image """
! 247: return self._getImageSize(self.filename)[1]
! 248:
! 249: security.declareProtected(ViewPermission, 'prev_width')
! 250: def prev_width(self):
! 251: """ Pixel width of the preview """
! 252: return self._getImageSize(self.prev_filename)[0]
! 253:
! 254: security.declareProtected(ViewPermission, 'prev_height')
! 255: def prev_height(self):
! 256: """ Pixel height of the preview """
! 257: return self._getImageSize(self.prev_filename)[1]
! 258:
! 259: security.declareProtected(ViewPermission, 'format')
! 260: def format(self):
! 261: """ Get the PIL file format of the image """
! 262: filename = self._get_fsname(self.filename)
! 263: try:
! 264: from PIL import Image
! 265: im = Image.open(filename)
! 266: return im.format
! 267: except:
! 268: return 'unknown'
! 269:
! 270: security.declareProtected(AccessPermission, 'get_prev_filename')
! 271: def get_prev_filename(self):
! 272: """ Returns the preview file name for display """
! 273: return self._fsname(self.prev_filename)
! 274:
! 275: ################################
! 276: # Protected management methods #
! 277: ################################
! 278:
! 279: # Management Interface
! 280: security.declareProtected(AccessPermission, 'manage_main')
! 281: manage_main = HTMLFile('dtml/extImageEdit', globals())
! 282:
! 283: security.declareProtected(ChangePermission, 'manage_del_prev')
! 284: def manage_del_prev(self, REQUEST=None):
! 285: """ Delete the Preview Image """
! 286: if self.has_preview and self.filename != self.prev_filename:
! 287: tmp_fn = self._temp_fsname(self.prev_filename)
! 288: fn = self._fsname(self.prev_filename)
! 289: if isfile(tmp_fn):
! 290: try: os.rename(tmp_fn, fn+'.undo')
! 291: except OSError: pass
! 292: else:
! 293: try: os.remove(fn)
! 294: except OSError: pass
! 295: elif isfile(fn):
! 296: try: os.rename(fn, fn+'.undo')
! 297: except OSError: pass
! 298: self.prev_content_type = ''
! 299: self.has_preview = 0
! 300:
! 301: self.ZCacheable_invalidate()
! 302:
! 303: if REQUEST is not None:
! 304: return self.manage_main(self, REQUEST, manage_tabs_message='Preview deleted.')
! 305:
! 306: security.declareProtected(ChangePermission, 'manage_create_prev')
! 307: def manage_create_prev(self, maxx=0, maxy=0, ratio=0, REQUEST=None):
! 308: """ Create a preview Image """
! 309: maxx, maxy = self._formatDimensions(maxx, maxy)
! 310: if maxx!=0 and maxy!=0:
! 311: self._register() # Register with TM
! 312: try:
! 313: new_fn = self._get_ufn(self.prev_filename, content_type='image/jpeg')
! 314: self._createPreview(self.filename, new_fn, maxx, maxy, ratio)
! 315: finally:
! 316: self._dir__unlock()
! 317: if REQUEST is None:
! 318: return self.has_preview
! 319: else:
! 320: if self.has_preview:
! 321: return self.manage_main(self, REQUEST, manage_tabs_message='Preview created.')
! 322: elif maxx=='0' and maxy=='0':
! 323: return MessageDialog(
! 324: title = 'Attention',
! 325: message = "You must enter a value > 0",
! 326: action = './manage_main',)
! 327: else:
! 328: return MessageDialog(
! 329: title = 'Warning',
! 330: message = "An error occurred while generating the preview.",
! 331: action = './manage_main',)
! 332:
! 333: # File upload Interface
! 334: security.declareProtected(AccessPermission, 'manage_uploadForm')
! 335: manage_uploadForm = HTMLFile('dtml/extImageUpload', globals())
! 336:
! 337: security.declareProtected(ChangePermission, 'manage_upload')
! 338: def manage_upload(self, file='', content_type='', is_preview=0,
! 339: create_prev=NO_PREVIEW, maxx='', maxy='', ratio=0,
! 340: REQUEST=None):
! 341: """ Upload image from file handle or string buffer """
! 342: if self.wl_isLocked():
! 343: raise ResourceLockedError, "File is locked via WebDAV"
! 344:
! 345: if type(file) == types.StringType:
! 346: temp_file = TemporaryFile()
! 347: temp_file.write(file)
! 348: temp_file.seek(0)
! 349: else:
! 350: temp_file = file
! 351: return self.manage_file_upload(temp_file, content_type, is_preview,
! 352: create_prev, maxx, maxy, ratio, REQUEST)
! 353:
! 354: security.declareProtected(ChangePermission, 'manage_file_upload')
! 355: def manage_file_upload(self, file='', content_type='', is_preview=0,
! 356: create_prev=NO_PREVIEW, maxx='', maxy='', ratio=0,
! 357: REQUEST=None):
! 358: """ Upload image from file handle or local directory """
! 359: if self.wl_isLocked():
! 360: raise ResourceLockedError, "File is locked via WebDAV"
! 361:
! 362: if is_preview:
! 363: if type(file) == types.StringType:
! 364: cant_read_exc = "Can't open: "
! 365: try: file = open(file, 'rb')
! 366: except: raise cant_read_exc, file
! 367: maxx, maxy = self._formatDimensions(maxx, maxy)
! 368: if create_prev==UPLOAD_RESIZE and maxx!=0 and maxy!=0:
! 369: self._register() # Register with TM
! 370: try:
! 371: new_fn = self._get_ufn(self.prev_filename, content_type='image/jpeg')
! 372: self._update_data(file, self._temp_fsname(new_fn))
! 373: finally:
! 374: self._dir__unlock()
! 375: self._createPreview(new_fn, new_fn, maxx, maxy, ratio)
! 376: else:
! 377: if content_type:
! 378: file = HTTPUpload(file, content_type)
! 379: self.prev_content_type = self._get_content_type(file, file.read(100),
! 380: self.id, self.prev_content_type)
! 381: file.seek(0)
! 382: self._register() # Register with TM
! 383: try:
! 384: new_fn = self._get_ufn(self.prev_filename, content_type=self.prev_content_type)
! 385: self._update_data(file, self._temp_fsname(new_fn))
! 386: finally:
! 387: self._dir__unlock()
! 388: self.prev_filename = new_fn
! 389: self._initPreview()
! 390: else:
! 391: ExtImage.inheritedAttribute("manage_file_upload")(self, file, content_type)
! 392: if create_prev==GENERATE:
! 393: maxx, maxy = self._formatDimensions(maxx, maxy)
! 394: if maxx!=0 and maxy!=0:
! 395: self._register() # Register with TM
! 396: try:
! 397: new_fn = self._get_ufn(self.prev_filename, content_type='image/jpeg')
! 398: self._createPreview(self.filename, new_fn, maxx, maxy, ratio)
! 399: finally:
! 400: self._dir__unlock()
! 401: if REQUEST is not None:
! 402: return self.manage_main(self, REQUEST, manage_tabs_message='Upload complete.')
! 403:
! 404: security.declareProtected(ChangePermission, 'manage_http_upload')
! 405: def manage_http_upload(self, url, is_preview=0, REQUEST=None):
! 406: """ Upload image from http-server """
! 407: if self.wl_isLocked():
! 408: raise ResourceLockedError, "File is locked via WebDAV"
! 409:
! 410: if is_preview:
! 411: url = urllib.quote(url,'/:')
! 412: cant_read_exc = "Can't open: "
! 413: try: file = urllib.urlopen(url)
! 414: except: raise cant_read_exc, url
! 415: file = HTTPUpload(file)
! 416: self.prev_content_type = self._get_content_type(file, file.read(100),
! 417: self.id, self.prev_content_type)
! 418: file.seek(0)
! 419: self._register() # Register with TM
! 420: try:
! 421: new_fn = self._get_ufn(self.prev_filename, content_type=self.prev_content_type)
! 422: self._update_data(file, self._temp_fsname(new_fn))
! 423: finally:
! 424: self._dir__unlock()
! 425: self.prev_filename = new_fn
! 426: self._initPreview()
! 427: else:
! 428: ExtImage.inheritedAttribute("manage_http_upload")(self, url)
! 429: #if self.has_preview:
! 430: # maxx, maxy = self._formatDimensions(self.prev_maxx, self.prev_maxy)
! 431: # self._register() # Register with TM
! 432: # try:
! 433: # new_fn = self._get_ufn(self.prev_filename, content_type='image/jpeg')
! 434: # self._createPreview(self.filename, new_fn, maxx, maxy, self.prev_ratio)
! 435: # finally:
! 436: # self._dir__unlock()
! 437: if REQUEST is not None:
! 438: return self.manage_main(self, REQUEST, manage_tabs_message='Upload complete.')
! 439:
! 440: security.declareProtected(ChangePermission, 'PUT')
! 441: def PUT(self, REQUEST, RESPONSE):
! 442: """ Handle HTTP PUT requests """
! 443: RESPONSE = ExtImage.inheritedAttribute("PUT")(self, REQUEST, RESPONSE)
! 444: if self.has_preview:
! 445: maxx, maxy = self._formatDimensions(self.prev_maxx, self.prev_maxy)
! 446: self._register() # Register with TM
! 447: try:
! 448: # Need to pass in the path as webdav.NullResource calls PUT
! 449: # on an unwrapped object.
! 450: try:
! 451: self.aq_parent # This raises AttributeError if no context
! 452: except AttributError:
! 453: path = self._get_zodb_path(REQUEST.PARENTS[0])
! 454: else:
! 455: path = None
! 456: new_fn = self._get_ufn(self.prev_filename, content_type='image/jpeg', path=path)
! 457: self._createPreview(self.filename, new_fn, maxx, maxy, self.prev_ratio)
! 458: finally:
! 459: self._dir__unlock()
! 460: return RESPONSE
! 461:
! 462: ################################
! 463: # Private methods #
! 464: ################################
! 465:
! 466: def _getImageSize(self, filename):
! 467: """ Return width, height tuple using PIL """
! 468: filename = self._get_fsname(filename)
! 469: try:
! 470: from PIL import Image
! 471: im = Image.open(filename)
! 472: return im.size[0], im.size[1]
! 473: except:
! 474: return 0, 0
! 475:
! 476: def _createPreview(self, from_filename, to_filename, maxx, maxy, ratio):
! 477: """ Generate a preview using PIL """
! 478: try:
! 479: from PIL import Image
! 480: except ImportError:
! 481: pass
! 482: else:
! 483: imfile = self._get_fsname(from_filename)
! 484: if imfile:
! 485: im = Image.open(imfile)
! 486: if im.mode!='RGB':
! 487: im = im.convert('RGB')
! 488: filter = Image.BICUBIC
! 489: if hasattr(Image, 'ANTIALIAS'): # PIL 1.1.3
! 490: filter = Image.ANTIALIAS
! 491: if ratio: # keep aspect-ratio
! 492: im.thumbnail((maxx,maxy), filter)
! 493: else: # distort to fixed size
! 494: im = im.resize((maxx,maxy), filter)
! 495: umask = os.umask(REPOSITORY_UMASK)
! 496: outfile = self._temp_fsname(to_filename)
! 497: try:
! 498: im.save(outfile, 'JPEG', quality=85)
! 499: except:
! 500: os.umask(umask)
! 501: if isfile(outfile):
! 502: try: os.remove(outfile)
! 503: except OSError: pass
! 504: raise
! 505: else:
! 506: os.umask(umask)
! 507: self.prev_content_type = 'image/jpeg'
! 508: self.prev_filename = to_filename
! 509: self.prev_maxx = maxx
! 510: self.prev_maxy = maxy
! 511: self.prev_ratio = ratio
! 512: self._initPreview()
! 513:
! 514: def _initPreview(self):
! 515: """ Verify the preview """
! 516: self.ZCacheable_invalidate()
! 517:
! 518: prev_width, prev_height = self._getImageSize(self.prev_filename)
! 519: if prev_width<=0 or prev_height<=0:
! 520: self.has_preview = 0
! 521: else:
! 522: self.has_preview = 1
! 523:
! 524: def _formatDimensions(self, maxx, maxy):
! 525: """ Make sure, the dimensions are valid int's """
! 526: if type(maxx) is types.StringType:
! 527: try: maxx = int(maxx)
! 528: except ValueError: maxx = self._image_size['default']
! 529: if type(maxy) is types.StringType:
! 530: try: maxy = int(maxy)
! 531: except ValueError: maxy = self._image_size['default']
! 532: if maxx!=0 and maxy!=0:
! 533: if maxx<self._image_size['min']: maxx = self._image_size['min']
! 534: elif maxx>self._image_size['max']: maxx = self._image_size['max']
! 535: if maxy<self._image_size['min']: maxy = self._image_size['min']
! 536: elif maxy>self._image_size['max']: maxy = self._image_size['max']
! 537: return maxx, maxy
! 538:
! 539: def _undo(self):
! 540: """ Restore filename after delete or copy-paste """
! 541: if self.has_preview and self.filename != self.prev_filename:
! 542: fn = self._fsname(self.prev_filename)
! 543: if not isfile(fn) and isfile(fn+'.undo'):
! 544: self._register() # Register with TM
! 545: os.rename(fn+'.undo', self._temp_fsname(self.prev_filename))
! 546: return ExtImage.inheritedAttribute("_undo")(self)
! 547:
! 548: def _get_content_type(self, file, body, id, content_type=None):
! 549: """ Determine the mime-type """
! 550: from OFS.Image import getImageInfo
! 551: ct, w, h = getImageInfo(body)
! 552: if ct:
! 553: content_type = ct
! 554: else:
! 555: content_type = ExtImage.inheritedAttribute('_get_content_type')(self,
! 556: file, body, id, content_type)
! 557: return content_type
! 558:
! 559: ################################
! 560: # Special management methods #
! 561: ################################
! 562:
! 563: security.declarePrivate('manage_afterClone')
! 564: def manage_afterClone(self, item):
! 565: """ When a copy of the object is created (zope copy-paste-operation),
! 566: this function is called by CopySupport.py. A copy of the external
! 567: file is created and self.filename is changed.
! 568: """
! 569: try:
! 570: self.aq_parent # This raises AttributeError if no context
! 571: except AttributeError:
! 572: pass
! 573: else:
! 574: result = ExtImage.inheritedAttribute("manage_afterClone")(self, item)
! 575: self._register() # Register with TM
! 576: try:
! 577: new_prev_fn = self._get_new_ufn(content_type=self.prev_content_type)
! 578: if self.has_preview and self.filename != self.prev_filename:
! 579: old_prev_fn = self._get_fsname(self.prev_filename)
! 580: if old_prev_fn:
! 581: self._update_data(old_prev_fn, self._temp_fsname(new_prev_fn))
! 582: self.prev_filename = new_prev_fn
! 583: else:
! 584: self.prev_filename = []
! 585: self.has_preview = 0
! 586: elif self.has_preview:
! 587: # XXX: This seems to be an impossible state?
! 588: old_fn = self._get_fsname(self.filename)
! 589: if not old_fn:
! 590: self.prev_filename = []
! 591: self.has_preview = 0
! 592: else:
! 593: self.prev_filename = []
! 594: finally:
! 595: self._dir__unlock()
! 596: return result
! 597: return ExtImage.inheritedAttribute("manage_afterClone")(self, item)
! 598:
! 599: security.declarePrivate('manage_afterAdd')
! 600: def manage_afterAdd(self, item, container):
! 601: """ When a copy of the object is created (zope copy-paste-operation),
! 602: this function is called by CopySupport.py. A copy of the external
! 603: file is created and self.filename is changed.
! 604: """
! 605: return ExtImage.inheritedAttribute("manage_afterAdd")(self, item, container)
! 606:
! 607: security.declarePrivate('manage_beforeDelete')
! 608: def manage_beforeDelete(self, item, container):
! 609: """ This method is called, when the object is deleted. To support
! 610: undo-functionality and because this happens too, when the object
! 611: is moved (cut-paste) or renamed, the external file is not deleted.
! 612: It is just renamed to filename.undo and remains in the
! 613: repository, until it is deleted manually.
! 614: """
! 615: if self.has_preview and self.filename != self.prev_filename:
! 616: tmp_fn = self._temp_fsname(self.prev_filename)
! 617: fn = self._fsname(self.prev_filename)
! 618: if isfile(tmp_fn):
! 619: try: os.rename(tmp_fn, fn+'.undo')
! 620: except OSError: pass
! 621: else:
! 622: try: os.remove(fn)
! 623: except OSError: pass
! 624: elif isfile(fn):
! 625: try: os.rename(fn, fn+'.undo')
! 626: except OSError: pass
! 627: return ExtImage.inheritedAttribute("manage_beforeDelete")(self, item, container)
! 628:
! 629: ################################
! 630: # Transaction manager methods #
! 631: ################################
! 632:
! 633: def _finish(self):
! 634: """ Commits the temporary file """
! 635: if self.prev_filename and self.filename != self.prev_filename:
! 636: tmp_fn = self._temp_fsname(self.prev_filename)
! 637: if _debug: LOG(_SUBSYS, INFO, 'finishing %s' % tmp_fn)
! 638: if isfile(tmp_fn):
! 639: if _debug: LOG(_SUBSYS, INFO, 'isfile %s' % tmp_fn)
! 640: fn = self._fsname(self.prev_filename)
! 641: try: os.remove(fn)
! 642: except OSError: pass
! 643: os.rename(tmp_fn, fn)
! 644: ExtImage.inheritedAttribute('_finish')(self)
! 645:
! 646: def _abort(self):
! 647: """ Deletes the temporary file """
! 648: if self.prev_filename and self.filename != self.prev_filename:
! 649: tmp_fn = self._temp_fsname(self.prev_filename)
! 650: if _debug: LOG(_SUBSYS, INFO, 'aborting %s' % tmp_fn)
! 651: if isfile(tmp_fn):
! 652: if _debug: LOG(_SUBSYS, INFO, 'isfile %s' % tmp_fn)
! 653: try: os.remove(tmp_fn)
! 654: except OSError: pass
! 655: ExtImage.inheritedAttribute('_abort')(self)
! 656:
! 657:
! 658: InitializeClass(ExtImage)
! 659:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>