+2004-10-05 Helge Hess <helge.hess@opengroupware.org>
+
+ * v0.9.18
+
+ * UIxMailPartViewer.m: added support methods for caches, added -sleep
+ method
+
+ * added multipart/alternative viewer
+
+ * added Thunderbird message read/unread icons
+
2004-10-04 Helge Hess <helge.hess@opengroupware.org>
* fixed fetching of mails with only text content (v0.9.17)
UIxMailView.m \
UIxMailEditor.m \
\
- UIxMailPartViewer.m \
- UIxMailPartTextViewer.m \
- UIxMailPartImageViewer.m\
- UIxMailPartMixedViewer.m
+ UIxMailPartViewer.m \
+ UIxMailPartTextViewer.m \
+ UIxMailPartImageViewer.m \
+ UIxMailPartMixedViewer.m \
+ UIxMailPartAlternativeViewer.m \
MailerUI_RESOURCE_FILES += \
Version \
UIxMailPartTextViewer.wox \
UIxMailPartMixedViewer.wox \
UIxMailPartImageViewer.wox \
+ UIxMailPartAlternativeViewer.wox\
MailerUI_RESOURCE_FILES += \
uix.css \
Images/tbtv_*.gif \
Images/icon_*.gif \
Images/tbtb_*.png \
+ Images/message-mail*.png\
Images/lori_32x32.png \
MailerUI_LOCALIZED_RESOURCE_FILES += \
Notes
=====
+- we might want to bind the content viewers as SOPE methods to the mail class?
+ eg "viewTextPlain"
+ - this would not return a WOComponent, but a SoPageInvocation
+ - caching might be more difficult
+ - some 'reuse component' support in SoPageInvocation for stateless
+ components?
+ - watch nested calls
+ - for this we would need to add support for embedded calling of SOPE methods
+ <var:component method="viewTextPlain" /> ?
+
Bodystructures
==============
--- /dev/null
+/*
+ Copyright (C) 2004 SKYRIX Software AG
+
+ This file is part of OpenGroupware.org.
+
+ OGo is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ OGo is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with OGo; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "UIxMailPartViewer.h"
+
+/*
+ UIxMailPartAlternativeViewer
+
+ Display multipart/alternative parts. Most common application is for messages
+ which contain text/html and text/plain, but it is also used in other
+ contexts, eg in OGo appointment mails.
+
+ TODO: We might want to give the user the possibility to access all parts
+ of the alternative set.
+*/
+
+@interface UIxMailPartAlternativeViewer : UIxMailPartViewer
+{
+ id childInfo;
+ unsigned int childIndex;
+}
+
+@end
+
+#include "UIxMailRenderingContext.h"
+#include "WOContext+UIxMailer.h"
+#include "common.h"
+
+@implementation UIxMailPartAlternativeViewer
+
+- (void)dealloc {
+ [self->childInfo release];
+ [super dealloc];
+}
+
+/* caches */
+
+- (void)resetBodyInfoCaches {
+ [self->childInfo release]; self->childInfo = nil;
+ self->childIndex = 0;
+ [super resetBodyInfoCaches];
+}
+
+/* part selection */
+
+- (NSArray *)childPartTypes {
+ NSMutableArray *types;
+ unsigned i, count;
+ NSArray *childParts;
+
+ childParts = [[self bodyInfo] valueForKey:@"parts"];
+ count = [childParts count];
+ types = [NSMutableArray arrayWithCapacity:count];
+
+ for (i = 0; i < count; i++) {
+ NSString *mt, *st;
+
+ mt = [[[childParts objectAtIndex:i] valueForKey:@"type"] lowercaseString];
+ st = [[[childParts objectAtIndex:i] valueForKey:@"subtype"]
+ lowercaseString];
+ mt = [[mt stringByAppendingString:@"/"] stringByAppendingString:st];
+ [types addObject:mt ? mt : (id)[NSNull null]];
+ }
+ return types;
+}
+
+- (int)selectPartIndexFromTypes:(NSArray *)_types {
+ /* returns the index of the selected part or NSNotFound */
+ unsigned i, count;
+
+ if ((count = [_types count]) == 0)
+ return NSNotFound;
+
+ /* we always choose text/plain if available */
+ if ((i = [_types indexOfObject:@"text/plain"]) != NSNotFound)
+ return i;
+
+ /* then we scan for other text types and choose the first one found */
+ for (i = 0; i < count; i++) {
+ if ([(NSString *)[_types objectAtIndex:i] hasPrefix:@"text/"])
+ return i;
+ }
+
+ /* as a fallback, we select the first available part */
+ return 0;
+}
+
+- (void)selectChildInfo {
+ unsigned idx;
+
+ [self->childInfo release]; self->childInfo = nil;
+ self->childIndex = 0;
+
+ idx = [self selectPartIndexFromTypes:[self childPartTypes]];
+ if (idx == NSNotFound) {
+ [self logWithFormat:@"ERROR: could not select a part of types: %@",
+ [self childPartTypes]];
+ return;
+ }
+
+ self->childIndex = idx + 1;
+ self->childInfo =
+ [[[[self bodyInfo] valueForKey:@"parts"] objectAtIndex:idx] retain];
+}
+
+/* accessors */
+
+- (id)childInfo {
+ if (self->childInfo == nil)
+ [self selectChildInfo];
+
+ return self->childInfo;
+}
+
+- (unsigned int)childIndex {
+ if (self->childIndex == 0)
+ [self selectChildInfo];
+
+ return self->childIndex - 1;
+}
+
+- (NSString *)childPartName {
+ unsigned char buf[8];
+ sprintf(buf, "%d", [self childIndex] + 1);
+ return [NSString stringWithCString:buf];
+}
+
+- (id)childPartPath {
+ NSArray *pp;
+
+ pp = [self partPath];
+ return [pp count] > 0
+ ? [pp arrayByAddingObject:[self childPartName]]
+ : [NSArray arrayWithObject:[self childPartName]];
+}
+
+/* nested viewers */
+
+- (id)contentViewerComponent {
+ id info;
+
+ info = [self childInfo];
+ return [[[self context] mailRenderingContext] viewerForBodyInfo:info];
+}
+
+@end /* UIxMailPartAlternativeViewer */
--- /dev/null
+<?xml version="1.0" standalone="yes"?>
+<div xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:var="http://www.skyrix.com/od/binding"
+ xmlns:const="http://www.skyrix.com/od/constant"
+ xmlns:rsrc="OGo:url"
+ xmlns:label="OGo:label"
+>
+ <div>
+ <var:component value="contentViewerComponent"
+ bodyInfo="childInfo"
+ partPath="childPartPath" />
+ </div>
+</div>
[super dealloc];
}
-/* notifications */
+/* caches */
-- (void)sleep {
+- (void)resetBodyInfoCaches {
[self->childInfo release]; self->childInfo = nil;
- [super sleep];
+ [super resetBodyInfoCaches];
}
/* accessors */
- (NSData *)flatContent;
+/* caches */
+
+- (void)resetPathCaches;
+- (void)resetBodyInfoCaches;
+
@end
#endif /* __Mailer_UIxMailPartViewer_H__ */
[super dealloc];
}
+/* caches */
+
+- (void)resetPathCaches {
+ [self->flatContent release]; self->flatContent = nil;
+}
+- (void)resetBodyInfoCaches {
+}
+
+/* notifications */
+
+- (void)sleep {
+ [self resetPathCaches];
+ [self resetBodyInfoCaches];
+ [self->partPath release]; self->partPath = nil;
+ [self->bodyInfo release]; self->bodyInfo = nil;
+ [super sleep];
+}
+
/* accessors */
- (void)setPartPath:(NSArray *)_path {
+ if ([_path isEqual:self->partPath])
+ return;
+
ASSIGN(self->partPath, _path);
+ [self resetPathCaches];
}
- (NSArray *)partPath {
return self->partPath;
WOComponent *viewer; /* non-retained! */
WOContext *context; /* non-retained! */
NSDictionary *flatContents; /* IMAP4 name to NSData */
-
+
+ WOComponent *alternativeViewer;
WOComponent *mixedViewer;
WOComponent *textViewer;
WOComponent *imageViewer;
}
- (void)dealloc {
+ [self->alternativeViewer release];
[self->mixedViewer release];
[self->textViewer release];
[self->imageViewer release];
/* resetting state */
- (void)reset {
- [self->flatContents release]; self->flatContents = nil;
- [self->mixedViewer release]; self->mixedViewer = nil;
- [self->textViewer release]; self->textViewer = nil;
- [self->imageViewer release]; self->imageViewer = nil;
+ [self->flatContents release]; self->flatContents = nil;
+ [self->alternativeViewer release]; self->alternativeViewer = nil;
+ [self->mixedViewer release]; self->mixedViewer = nil;
+ [self->textViewer release]; self->textViewer = nil;
+ [self->imageViewer release]; self->imageViewer = nil;
}
/* fetching */
return self->mixedViewer;
}
+- (WOComponent *)alternativeViewer {
+ if (self->alternativeViewer == nil) {
+ self->alternativeViewer =
+ [[self->viewer pageWithName:@"UIxMailPartAlternativeViewer"] retain];
+ }
+ return self->alternativeViewer;
+}
+
- (WOComponent *)textViewer {
if (self->textViewer == nil) {
self->textViewer =
return [self mixedViewer];
if ([st isEqualToString:@"signed"]) // TODO: temporary workaround
return [self mixedViewer];
+ if ([st isEqualToString:@"alternative"])
+ return [self alternativeViewer];
}
else if ([mt isEqualToString:@"text"]) {
if ([st isEqualToString:@"plain"])
return [self textViewer];
+ if ([st isEqualToString:@"html"])
+ return [self textViewer]; // TODO: temporary workaround
}
else if ([mt isEqualToString:@"image"])
return [self imageViewer];
pgp-viewer
*/
}
-
+
+ // TODO: always fallback to octet viewer?!
[self logWithFormat:@"ERROR: found no viewer for MIME type: %@/%@", mt, st];
return nil;
}
# $Id$
-SUBMINOR_VERSION:=17
+SUBMINOR_VERSION:=18
div.mailer_readmailsubject {
/* TODO: use proper read icon */
- background-image: url(tbtv_leaf_corner_17x17.gif);
+ /* background-image: url(tbtv_leaf_corner_17x17.gif); */
+ background-image: url(message-mail-read.png);
background-repeat: no-repeat;
background-position: 0px 0px;
padding-top: 1px;
}
div.mailer_unreadmailsubject {
/* TODO: use proper unread icon */
- background-image: url(tbtv_leaf_corner_17x17.gif);
+ /* background-image: url(tbtv_leaf_corner_17x17.gif); */
+ background-image: url(message-mail.png);
background-repeat: no-repeat;
background-position: 0px 0px;
padding-left: 20px;
"tbtb_search.png",
"tbtb_trash.png",
+ "message-mail.png",
+ "message-mail-read.png",
+
"icon_mark_flagged.gif",
"icon_mark_read.gif",
"icon_mark_unflagged.gif",