]> err.no Git - scalable-opengroupware.org/blobdiff - UI/MailerUI/UIxMailTree.m
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1065 d1b88da0-ebda-0310...
[scalable-opengroupware.org] / UI / MailerUI / UIxMailTree.m
index a6538ec8798e9f68f32344234dbcd78c72d633b3..0204d4fd988de7f82965ab36fe7b0d93ae3d6244 100644 (file)
   02111-1307, USA.
 */
 
-#include <SOGoUI/UIxComponent.h>
+#import "common.h"
 
-@interface UIxMailTree : UIxComponent
-{
-  NSString *rootClassName;
-  NSString *treeFolderAction;
-  id rootNodes;
-  id item;
-}
-@end
+#import <SoObjects/Mailer/SOGoMailBaseObject.h>
+#import <SoObjects/Mailer/SOGoMailAccount.h>
+#import <SoObjects/Mailer/SOGoMailFolder.h>
+#import <NGObjWeb/SoComponent.h>
+#import <NGObjWeb/SoObject+SoDAV.h>
 
-#include "UIxMailTreeBlock.h"
-#include <SoObjects/Mailer/SOGoMailBaseObject.h>
-#include <SoObjects/Mailer/SOGoMailAccount.h>
-#include "common.h"
-#include <NGObjWeb/SoComponent.h>
-#include <NGObjWeb/SoObject+SoDAV.h>
+#import "UIxMailTree.h"
+#import "UIxMailTreeBlock.h"
 
 /*
   Support special icons:
 
 static BOOL debugBlocks = NO;
 
-+ (void)initialize {
++ (void)initialize
+{
   [UIxMailTreeBlock class]; // ensure that globals are initialized
 }
 
-- (void)dealloc {
-  [self->treeFolderAction release];
-  [self->rootClassName    release];
-  [self->rootNodes release];
-  [self->item      release];
+- (id) init
+{
+  if ((self = [super init]))
+    {
+      flattenedNodes = nil;
+    }
+
+  return self;
+}
+
+- (void) dealloc
+{
+  [treeFolderAction release];
+  [rootClassName release];
+  [rootNodes release];
+  [item release];
+  [flattenedNodes release];
   [super dealloc];
 }
 
 /* icons */
 
-- (NSString *)defaultIconName {
+- (NSString *) defaultIconName
+{
   return @"tbtv_leaf_corner_17x17.gif";
 }
 
@@ -88,24 +95,24 @@ static BOOL debugBlocks = NO;
 /* accessors */
 
 - (void)setRootClassName:(id)_rootClassName {
-  ASSIGNCOPY(self->rootClassName, _rootClassName);
+  ASSIGNCOPY(rootClassName, _rootClassName);
 }
 - (id)rootClassName {
-  return self->rootClassName;
+  return rootClassName;
 }
 
 - (void)setItem:(id)_item {
-  ASSIGN(self->item, _item);
+  ASSIGN(item, _item);
 }
 - (id)item {
-  return self->item;
+  return item;
 }
 
 - (void)setTreeFolderAction:(NSString *)_action {
-  ASSIGNCOPY(self->treeFolderAction, _action);
+  ASSIGNCOPY(treeFolderAction, _action);
 }
 - (NSString *)treeFolderAction {
-  return self->treeFolderAction;
+  return treeFolderAction;
 }
 
 - (NSString *)itemIconName {
@@ -133,21 +140,35 @@ static BOOL debugBlocks = NO;
     [self logWithFormat:@"to-many: %@ %@", _object,
          [names componentsJoinedByString:@","]];
   }
-  
+
   count = [names count];
   ma    = [NSMutableArray arrayWithCapacity:(count + 1)];
   for (i = 0; i < count; i++) {
     id folder;
     
+    // TODO: use some context or reuse the main context?
     folder = [_object lookupName:[names objectAtIndex:i] inContext:nil 
                      acquire:NO];
-    if (folder == nil)
+    if (folder == nil) {
+      if (debugBlocks) {
+       [self logWithFormat:@"  DID NOT FIND FOLDER %@: %@",
+               _object,
+               [names objectAtIndex:i]];
+      }
       continue;
-    if ([folder isKindOfClass:[NSException class]])
+    }
+    if ([folder isKindOfClass:[NSException class]]) {
+      if (debugBlocks) {
+       [self logWithFormat:@"  FOLDER LOOKUP EXCEPTION %@: %@",
+               [names objectAtIndex:i], folder];
+      }
       continue;
+    }
     
     [ma addObject:folder];
   }
+  if (debugBlocks)
+    [self logWithFormat:@"  returning: %@ %@", _object, ma];
   return ma;
 }
 
@@ -166,40 +187,48 @@ static BOOL debugBlocks = NO;
   return [_object isKindOfClass:NSClassFromString([self rootClassName])];
 }
 
-- (NSString *)treeNavigationLinkForObject:(id)_object atDepth:(int)_depth {
-  NSString *link;
-  unsigned i;
-  
-  link = [[_object nameInContainer] stringByAppendingString:@"/"];
-  link = [link stringByAppendingString:[self treeFolderAction]];
-  
-  switch (_depth) {
-  case 0: return link;
-  case 1: return [@"../"       stringByAppendingString:link];
-  case 2: return [@"../../"    stringByAppendingString:link];
-  case 3: return [@"../../../" stringByAppendingString:link];
-  }
+- (NSString *)treeNavigationLinkForObject:(id)_object
+                                 atDepth:(int)_depth
+{
+  NSMutableString *link;
+  int i;
   
+  link = [NSMutableString new];
+  [link autorelease];
+
   for (i = 0; i < _depth; i++)
-    link = [@"../" stringByAppendingString:link];
+    [link appendString: @"../"];
+
+  [link appendFormat: @"%@/%@",
+       [_object nameInContainer],
+       [self treeFolderAction]];
+  
   return link;
 }
 
-- (void)getTitle:(NSString **)_t andIcon:(NSString **)_icon
-  forObject:(id)_object
+- (void) getTitle: (NSString **)_t
+       folderType: (NSString **)_ft
+         andIcon: (NSString **)_icon
+       forObject: (id)_object
 {
   // TODO: need to refactor for reuse!
   NSString *ftype;
   unsigned len;
+
+//   if ([_object respondsToSelector: @selector (outlookFolderClass)])
+//     ftype = [_object outlookFolderClass];
+//   else
+    ftype = [_object valueForKey:@"outlookFolderClass"];
+  len = [ftype length];
   
-  ftype = [_object valueForKey:@"outlookFolderClass"];
-  len   = [ftype length];
-  
+  *_ft = nil;
+
   switch (len) {
   case 8:
     if ([ftype isEqualToString:@"IPF.Sent"]) {
       *_t = [self labelForKey:@"SentFolderName"];
       *_icon = @"tbtv_sent_17x17.gif";
+      *_ft = @"sent";
       return;
     }
     break;
@@ -207,11 +236,13 @@ static BOOL debugBlocks = NO;
     if ([ftype isEqualToString:@"IPF.Inbox"]) {
       *_t = [self labelForKey:@"InboxFolderName"];
       *_icon = @"tbtv_inbox_17x17.gif";
+      *_ft = @"inbox";
       return;
     }
     if ([ftype isEqualToString:@"IPF.Trash"]) {
       *_t = [self labelForKey:@"TrashFolderName"];
       *_icon = @"tbtv_trash_17x17.gif";
+      *_ft = @"trash";
       return;
     }
     break;
@@ -219,44 +250,48 @@ static BOOL debugBlocks = NO;
     if ([ftype isEqualToString:@"IPF.Drafts"]) {
       *_t = [self labelForKey:@"DraftsFolderName"];
       *_icon = @"tbtv_drafts_17x17.gif";
+      *_ft = @"drafts";
       return;
     }
-    if ([ftype isEqualToString:@"IPF.Filter"]) {
-      *_t = [self labelForKey:@"SieveFolderName"];
-      *_icon = nil;
-      return;
-    }
+//     if ([ftype isEqualToString:@"IPF.Filter"]) {
+//       *_t = [self labelForKey:@"SieveFolderName"];
+//       *_icon = nil;
+//       *_ft = @"sieve";
+//       return;
+//     }
     break;
   }
-  
+
   *_t    = [_object davDisplayName];
   *_icon = nil;
   
   if ([_object isKindOfClass:NSClassFromString(@"SOGoMailFolder")])
     *_icon = nil;
   else if ([_object isKindOfClass:NSClassFromString(@"SOGoMailAccount")]) {
-    *_icon = @"tbtv_inbox_17x17.gif";
+    *_icon = @"tbtv_account_17x17.gif";
+
+    *_ft = @"account";
     
     /* title processing is somehow Agenor specific and should be done in UI */
     *_t = [[_object nameInContainer] titleForSOGoIMAP4String];
   }
   else if ([_object isKindOfClass:NSClassFromString(@"SOGoMailAccounts")])
-    *_icon = @"tbtv_inbox_17x17.gif";
+    *_icon = @"tbtv_account_17x17.gif";
   else if ([_object isKindOfClass:NSClassFromString(@"SOGoUserFolder")])
     *_icon = @"tbtv_inbox_17x17.gif";
   else {
     // TODO: use drafts icon for other SOGo folders
     *_icon = @"tbtv_drafts_17x17.gif";
   }
-  
-  return;
 }
 
-- (UIxMailTreeBlock *)treeNavigationBlockForLeafNode:(id)_o atDepth:(int)_d {
+- (UIxMailTreeBlock *) treeNavigationBlockForLeafNode: (id) _o
+                                             atDepth: (int) _d
+{
   UIxMailTreeBlock *md;
-  NSString *n, *i;
+  NSString *n, *i, *ft;
   id blocks;
-  
+
   /* 
      Trigger plus in treeview if it has subfolders. It is an optimization that
      we do not generate blocks for folders which are not displayed anyway.
@@ -264,14 +299,16 @@ static BOOL debugBlocks = NO;
   blocks = [[_o toManyRelationshipKeys] count] > 0
     ? UIxMailTreeHasChildrenMarker
     : nil;
-  
-  [self getTitle:&n andIcon:&i forObject:_o];
-  
-  md = [UIxMailTreeBlock blockWithName:nil
-                        title:n iconName:i
-                        link:[self treeNavigationLinkForObject:_o atDepth:_d]
-                        isPathNode:NO isActiveNode:NO
-                        childBlocks:blocks];
+
+  [self getTitle: &n folderType: &ft andIcon: &i forObject:_o];
+
+  md = [UIxMailTreeBlock blockWithName: nil
+                        title: n
+                        iconName: i
+                        link: [self treeNavigationLinkForObject:_o atDepth:_d]
+                        isPathNode:NO
+                        isActiveNode:NO
+                        childBlocks: blocks];
   return md;
 }
 
@@ -283,7 +320,7 @@ static BOOL debugBlocks = NO;
   UIxMailTreeBlock *md;
   NSMutableArray   *blocks;
   NSArray          *folders;
-  NSString         *title, *icon;
+  NSString         *title, *icon, *ft;
   unsigned         i, count;
 
   if (debugBlocks) {
@@ -299,7 +336,7 @@ static BOOL debugBlocks = NO;
   for (i = 0; i < count; i++) {
     id block;
     
-    block = [self treeNavigationBlockForLeafNode:[folders objectAtIndex:i]
+    block = [self treeNavigationBlockForLeafNode: [folders objectAtIndex:i]
                  atDepth:0];
     if ([block isNotNull]) [blocks addObject:block];
   }
@@ -308,17 +345,63 @@ static BOOL debugBlocks = NO;
   
   /* build block */
   
-  [self getTitle:&title andIcon:&icon forObject:_object];
-  md = [UIxMailTreeBlock blockWithName:[_object nameInContainer]
-                        title:title iconName:icon
-                        link:[@"../" stringByAppendingString:
-                                 [_object nameInContainer]]
-                        isPathNode:YES isActiveNode:YES
-                        childBlocks:blocks];
+  [self getTitle:&title folderType: &ft andIcon:&icon forObject:_object];
+
+  md = [UIxMailTreeBlock blockWithName: [_object nameInContainer]
+                        title: title
+                        iconName: icon
+                        link: [@"../" stringByAppendingString:
+                                  [_object nameInContainer]]
+                        isPathNode: YES
+                        isActiveNode: YES
+                        childBlocks: blocks];
   return md;
 }
 
-- (UIxMailTreeBlock *)treeNavigationBlockForActiveNode:(id)_object {
+- (UIxMailTreeBlock *) fullTreeNavigationBlockForNode: (id)_object
+{
+  UIxMailTreeBlock *md;
+  NSMutableArray   *blocks;
+  NSArray          *folders;
+  NSString         *title, *icon, *ft;
+  unsigned         i, count;
+
+  if (debugBlocks)
+    [self logWithFormat:@"block for root node 0x%08X<%@>", 
+           _object, NSStringFromClass([_object class])];
+  
+  folders = [self fetchSubfoldersOfObject: _object];
+  count   = [folders count];
+  blocks  = [NSMutableArray arrayWithCapacity: count];
+  for (i = 0; i < count; i++)
+    {
+      id block;
+    
+      block = [self fullTreeNavigationBlockForNode: [folders objectAtIndex:i]];
+      if ([block isNotNull]) [blocks addObject:block];
+    }
+
+  if (![blocks count])
+    blocks = nil;
+  
+  [self getTitle: &title folderType: &ft andIcon: &icon forObject: _object];
+//   NSLog (@"*********** title = '%@'/icon = '%@'", title, icon);
+
+  md = [UIxMailTreeBlock blockWithName: [_object nameInContainer]
+                        title: title
+                        iconName: icon
+                        link: [@"../" stringByAppendingString:
+                                  [_object nameInContainer]]
+                        isPathNode: YES
+                        isActiveNode: YES
+                        childBlocks: blocks];
+  [md setFolderType: ft];
+
+  return md;
+}
+
+- (UIxMailTreeBlock *) treeNavigationBlockForActiveNode: (id) _object
+{
   /* 
      This generates the block for the clientObject (the object which has the 
      focus)
@@ -326,7 +409,7 @@ static BOOL debugBlocks = NO;
   UIxMailTreeBlock *md;
   NSMutableArray   *blocks;
   NSArray  *folders;
-  NSString *title, *icon;
+  NSString *title, *icon, *ft;
   unsigned i, count;
 
   // TODO: maybe we can join the two implementations, this might not be
@@ -348,26 +431,29 @@ static BOOL debugBlocks = NO;
   for (i = 0; i < count; i++) {
     UIxMailTreeBlock *block;
     
-    block = [self treeNavigationBlockForLeafNode:[folders objectAtIndex:i]
-                 atDepth:0];
+    block = [self treeNavigationBlockForLeafNode: [folders objectAtIndex:i]
+                 atDepth: 0];
     if ([block isNotNull]) [blocks addObject:block];
   }
   if ([blocks count] == 0) blocks = nil;
-  
+
   /* build block */
   
-  [self getTitle:&title andIcon:&icon forObject:_object];
-  md = [UIxMailTreeBlock blockWithName:[_object nameInContainer]
-                        title:title iconName:icon
-                        link:@"."
-                        isPathNode:YES isActiveNode:YES
-                        childBlocks:blocks];
+  [self getTitle:&title folderType: &ft andIcon:&icon forObject:_object];
+  md = [UIxMailTreeBlock blockWithName: [_object nameInContainer]
+                        title: title
+                        iconName: icon
+                        link: @"."
+                        isPathNode: YES
+                        isActiveNode: YES
+                        childBlocks: blocks];
   return md;
 }
 
-- (UIxMailTreeBlock *)treeNavigationBlockForObject:(id)_object
-  withActiveChildBlock:(UIxMailTreeBlock *)_activeChildBlock 
-  depth:(int)_depth
+- (UIxMailTreeBlock *)
+  treeNavigationBlockForObject: (id) _object
+         withActiveChildBlock: (UIxMailTreeBlock *) _activeChildBlock 
+                        depth: (int) _depth
 {
   /*
     Note: 'activeChildBlock' here doesn't mean that the block is the selected
@@ -378,7 +464,7 @@ static BOOL debugBlocks = NO;
   NSMutableArray   *blocks;
   NSString         *activeName;
   NSArray          *folders;
-  NSString         *title, *icon;
+  NSString         *title, *icon, *ft;
   unsigned         i, count;
   
   activeName = [_activeChildBlock valueForKey:@"name"];
@@ -395,7 +481,8 @@ static BOOL debugBlocks = NO;
     folder = [folders objectAtIndex:i];
     block = [activeName isEqualToString:[folder nameInContainer]]
       ? _activeChildBlock
-      : [self treeNavigationBlockForLeafNode:folder atDepth:_depth];
+      : [self treeNavigationBlockForLeafNode: folder
+             atDepth:_depth];
     
     if ([block isNotNull]) [blocks addObject:block];
   }
@@ -405,17 +492,19 @@ static BOOL debugBlocks = NO;
     else
       blocks = nil;
   }
-  
+
   /* build block */
   
-  [self getTitle:&title andIcon:&icon forObject:_object];
-  resultBlock = [UIxMailTreeBlock blockWithName:[_object nameInContainer]
-                                 title:title iconName:icon
-                                 link:
-                                   [self treeNavigationLinkForObject:_object 
-                                         atDepth:(_depth + 1)] 
-                                 isPathNode:YES isActiveNode:NO
-                                 childBlocks:blocks];
+  [self getTitle:&title folderType: &ft andIcon:&icon forObject:_object];
+  resultBlock
+    = [UIxMailTreeBlock blockWithName: [_object nameInContainer]
+                       title: title
+                       iconName: icon
+                       link:
+                         [self treeNavigationLinkForObject: _object 
+                               atDepth: (_depth + 1)]
+                       isPathNode:YES isActiveNode:NO
+                       childBlocks:blocks];
   
   /* recurse up unless we are at the root */
 
@@ -458,7 +547,7 @@ static BOOL debugBlocks = NO;
   if (debugBlocks) [self logWithFormat:@"ACTIVE parent block ..."];
   block = [self treeNavigationBlockForObject:[_object container] 
                withActiveChildBlock:block
-               depth:1];
+               depth: 1];
   if (debugBlocks) [self logWithFormat:@"done: %@", block];
   return block;
 }
@@ -468,24 +557,90 @@ static BOOL debugBlocks = NO;
 - (NSArray *)rootNodes {
   UIxMailTreeBlock *navNode;
   
-  if (self->rootNodes != nil)
-    return self->rootNodes;
+  if (rootNodes != nil)
+    return rootNodes;
   
   navNode = [self buildNavigationNodesForObject:[self clientObject]];
   
   if ([navNode hasChildren] && [navNode areChildrenLoaded])
-    self->rootNodes = [[navNode children] retain];
+    rootNodes = [[navNode children] retain];
   else if (navNode)
-    self->rootNodes = [[NSArray alloc] initWithObjects:&navNode count:1];
+    rootNodes = [[NSArray alloc] initWithObjects:&navNode count:1];
   
-  return self->rootNodes;
+  return rootNodes;
+}
+
+- (int) addNodes: (NSArray *) nodes
+        atSerial: (int) startSerial
+       forParent: (int) parent
+    withRootName: (NSString *) rootName
+         toArray: (NSMutableArray *) array
+{
+  unsigned int count, max, currentSerial;
+  UIxMailTreeBlock *curNode;
+  NSString *fullName;
+
+  max = [nodes count];
+  currentSerial = startSerial;
+  for (count = 0; count < max; count++)
+    {
+      curNode = [nodes objectAtIndex: count];
+      fullName = [rootName stringByAppendingFormat: @"/%@", [curNode name]];
+      [curNode setName: fullName];
+      [curNode setSerial: currentSerial];
+      [curNode setParent: parent];
+      [array addObject: curNode];
+      if ([curNode hasChildren])
+        currentSerial = [self addNodes: [curNode children]
+                              atSerial: currentSerial + 1
+                              forParent: currentSerial
+                              withRootName: fullName
+                              toArray: array];
+      else
+        currentSerial++;
+    }
+
+  return currentSerial;
+}
+
+- (NSArray *) flattenedNodes
+{
+  UIxMailTreeBlock *rootNode; // , *curNode;
+  id mailAccounts;
+//   unsigned int count, max;
+
+  if (!flattenedNodes)
+    {
+      flattenedNodes = [NSMutableArray new];
+
+      if (![[self clientObject] isKindOfClass: NSClassFromString(@"SOGoMailAccounts")])
+       mailAccounts = [[self clientObject] mailAccountsFolder];
+      else
+       mailAccounts = [self clientObject];
+
+      rootNode = [self fullTreeNavigationBlockForNode: mailAccounts];
+      [self addNodes: [rootNode children]
+           atSerial: 1
+           forParent: 0
+           withRootName: @""
+           toArray: flattenedNodes];
+//       max = [flattenedBlocks count];
+//       for (count = 0; count < max; count++)
+//     {
+//       curNode = [flattenedBlocks objectAtIndex: count];
+//       NSLog (@"%d: %@/%@", count, [curNode title], [curNode iconName]);
+//     }
+    }
+
+  return flattenedNodes;
 }
 
 /* notifications */
 
-- (void)sleep {
-  [self->item      release]; self->item      = nil;
-  [self->rootNodes release]; self->rootNodes = nil;
+- (void) sleep
+{
+  [item release]; item = nil;
+  [rootNodes release]; rootNodes = nil;
   [super sleep];
 }