NSOutlineView autosaving of expanded/collapsed state

  • Hi,

    is there a solution on Leopard to implement the autosaving of expanded/
    collapsed state of an NSOutlineView (bound to Core Data via
    NSTreeController).
    I tried to implement outlineview:persistentObjectForItem; and
    outlineView:itemForPersistentObject:. But it doesnt't work, because
    NSTreeNode and NSManagedObject don't encode with NSKeyedArchiver.
    Is there something I am missing, or couldn't state autosaving be done
    in Leopard without 'hacks' like in Tiger?

    Ralph.
  • On 23 Feb 2008, at 01:58, Ralph Manns wrote:

    > Hi,
    >
    > is there a solution on Leopard to implement the autosaving of
    > expanded/collapsed state of an NSOutlineView (bound to Core Data via
    > NSTreeController).
    > I tried to implement outlineview:persistentObjectForItem; and
    > outlineView:itemForPersistentObject:. But it doesnt't work, because
    > NSTreeNode and NSManagedObject don't encode with NSKeyedArchiver.
    > Is there something I am missing, or couldn't state autosaving be
    > done in Leopard without 'hacks' like in Tiger?
    >

    Hi Ralph,

    I ran into this too in a non-Core Data app.  I haven't found a
    solution better than iterating through each row in the outlineView and
    calling -isItemExpanded (I think that's the method) so I can use the
    output from this to re-exapnd the rows when I restart my app (or open
    the document in  the case of a document-based app).

    I'd welcome a better solution though!

    Jon
  • Am 23.02.2008 um 23:44 schrieb Jonathan Dann:

    > On 23 Feb 2008, at 01:58, Ralph Manns wrote:
    >
    >> Hi,
    >>
    >> is there a solution on Leopard to implement the autosaving of
    >> expanded/collapsed state of an NSOutlineView (bound to Core Data
    >> via NSTreeController).
    >> I tried to implement outlineview:persistentObjectForItem; and
    >> outlineView:itemForPersistentObject:. But it doesnt't work, because
    >> NSTreeNode and NSManagedObject don't encode with NSKeyedArchiver.
    >> Is there something I am missing, or couldn't state autosaving be
    >> done in Leopard without 'hacks' like in Tiger?
    >>
    >
    > Hi Ralph,
    >
    > I ran into this too in a non-Core Data app.  I haven't found a
    > solution better than iterating through each row in the outlineView
    > and calling -isItemExpanded (I think that's the method) so I can use
    > the output from this to re-exapnd the rows when I restart my app (or
    > open the document in  the case of a document-based app).
    >
    > I'd welcome a better solution though!
    >
    > Jon

    Hi Jon,

    I haven't found a solution up to now, although I tried everything. So
    I have to do it like you explained.

    Ralph.
  • Hi Ralph,

    Here's my code from an NSOutlineView subclass

    - (NSArray *)expandedItems;
    {
    NSMutableArray *expandedItemsArray = [NSMutableArray array];
    NSUInteger row, numberOfRows = [self numberOfRows];

    for (row = 0 ; row < numberOfRows ; row++)
    {
      id item = [self itemAtRow:row];
      if ([self isItemExpanded:item])
      [expandedItemsArray addObject:[item representedObject]]; // create
    an array of only the expanded items in the list
    }

    return [[expandedItemsArray copy] autorelease];
    }

    The returned array can then be archived.

    It uses NSTreeNode and -representedObject, so is 10.5 only. For 10.4
    there is an undocumented method for the private class that
    NSTreeController used in 10.4 that does the same thing, can't remember
    the method name but it's on Scott Stevenson's blog somewhere, just
    Google theococoa.com and NSTreeController.

    Passing the (now unarchived) array to the method below will expand
    them again.

    - (void)expandItems:(NSArray *)array;
    {
    NSUInteger row, numberOfRows = [self numberOfRows];
    for (MyNode *savedItem in array) {
      for (row = 0 ; row < numberOfRows ; row++) {
      id item = [self itemAtRow:row];
      MyNode *realObject = [item representedObject];
      if ([realObject.nodeName isEqualToString:savedItem.nodeName]) {
        [self expandItem:item];
        numberOfRows = [self numberOfRows];
        break;
      }
      }
    }
    }

    Enjoy,

    Jon
  • Am 24.02.2008 um 23:37 schrieb Jonathan Dann:

    > Hi Ralph,
    >
    > Here's my code from an NSOutlineView subclass
    >
    > - (NSArray *)expandedItems;
    > {
    > NSMutableArray *expandedItemsArray = [NSMutableArray array];
    > NSUInteger row, numberOfRows = [self numberOfRows];
    >
    > for (row = 0 ; row < numberOfRows ; row++)
    > {
    > id item = [self itemAtRow:row];
    > if ([self isItemExpanded:item])
    > [expandedItemsArray addObject:[item representedObject]]; //
    > create an array of only the expanded items in the list
    > }
    >
    > return [[expandedItemsArray copy] autorelease];
    > }
    >
    > The returned array can then be archived.
    >
    > It uses NSTreeNode and -representedObject, so is 10.5 only. For 10.4
    > there is an undocumented method for the private class that
    > NSTreeController used in 10.4 that does the same thing, can't
    > remember the method name but it's on Scott Stevenson's blog
    > somewhere, just Google theococoa.com and NSTreeController.
    >
    > Passing the (now unarchived) array to the method below will expand
    > them again.
    >
    > - (void)expandItems:(NSArray *)array;
    > {
    > NSUInteger row, numberOfRows = [self numberOfRows];
    > for (MyNode *savedItem in array) {
    > for (row = 0 ; row < numberOfRows ; row++) {
    > id item = [self itemAtRow:row];
    > MyNode *realObject = [item representedObject];
    > if ([realObject.nodeName isEqualToString:savedItem.nodeName]) {
    > [self expandItem:item];
    > numberOfRows = [self numberOfRows];
    > break;
    > }
    > }
    > }
    > }
    >
    > Enjoy,
    >
    > Jon

    Hi Jon,

    thanks for your response and providing your code. Works great.

    Ralph.
  • > is there a solution [...] to implement the autosaving of expanded/
    > collapsed state of an NSOutlineView

    I haven't done much work with Core Data so apologies if this won't/
    doesn't work: I simply had a look at the headers.

    Couldn't you return [[aManagedObject objectID] URIRepresentation] in
    outlineView:persistentObjectForItem: to save the expanded state. Then
    restore it by returning [aManagedObjectContext objectWithID:
    [aPersistentStoreCoordinator managedObjectIDForURIRepresentation:URI]]
    from outlineView:itemForPersistentObject:?

    Keith
  • > Couldn't you return [[aManagedObject objectID] URIRepresentation] in
    > outlineView:persistentObjectForItem: to save the expanded state.
    > Then restore it by returning [aManagedObjectContext objectWithID:
    > [aPersistentStoreCoordinator
    > managedObjectIDForURIRepresentation:URI]] from
    > outlineView:itemForPersistentObject:?

      You can't rely on the the URI representation the way you might
    expect for any objects that haven't yet been saved. The
    URIRepresentation is based on the objectID. From the documentation:

    "If the receiver has not yet been saved, the object ID is a temporary
    value that will change when the object is saved."

      It's best to add an "expanded" attribute or something similarly
    named and rely on it instead.

    --
    I.S.
  • On 24 Feb 2008, at 22:45, Ralph Manns wrote:

    >
    > Am 24.02.2008 um 23:37 schrieb Jonathan Dann:
    >
    > Hi Jon,
    >
    > thanks for your response and providing your code. Works great.
    >
    > Ralph.

    You're welcome!

    Jon