NSTextView, partial views of NSTextStorage

  • I have a text view, and I want it to just display and edit a subrange
    of it's associated NSTextStorage. For example lets say my text
    storage has 10 paragraphs, but I just want my NSTextView to display
    and edit one of them. I also need the solution to scale to multiple
    NSTextViews, so for example one view will be viewing paragraphs 2-3,
    while another might be viewing paragraphs 3-4.

    I'm wondering what the best way to approach this problem is?

    Currently I'm doing it at the NSTextStorage level. I have a subclass
    of NSTextStorage that will observer and stay in synch with a subrange
    from another NSTextStorage. This works, but it's a bit complicated
    and it makes managing a universal undo stack hard since each
    NSTextView is associated with a different NSTextStorage.

    Two other approaches that I haven't tried, but I would love to hear
    thoughts on...

    1. First is it possible to subclass or tell NSLayoutManger to only
    work with a specific range and just layout that range in it's
    associated NSTextStorage? Using this approach I would just add a new
    NSLayoutManger to my NSTextStorage for each new NSTextView that I
    wanted. But by default it seems like NSLayoutMangers always like to
    start layout from the start of the NSTextStorage, and continue until
    the text views text container is full. I'd need a way to set hard
    start and end points.

    2. Or if the above isn't possible is it possible to tell a NSTextView
    to just draw and edit a subrange of it's text and ignore the rest?

    I'd love to hear thoughts on what solution would be best, and
    anything that I should be aware of before getting to deep into it.

    Thanks,
    Jesse
  • Hi Jesse,

    > 1. First is it possible to subclass or tell NSLayoutManger to only
    > work with a specific range and just layout that range in it's
    > associated NSTextStorage?

    This definitely isn't possible with the current public
    NSLayoutManager API. I've never tried anything like you want, but if
    you did dig into the private methods, I bet it would be a huge effort
    (or impossible) and much frustration. All the NSTextStorage APIs you
    need are public, so I'd stick with what you have.

    > 2. Or if the above isn't possible is it possible to tell a
    > NSTextView to just draw and edit a subrange of it's text and ignore
    > the rest?

    What you want isn't directly possible, but you could always construct
    a series of NSTextContainers to accomplish what you like. Basically
    you would just assign the NSTextView the container for the Nth
    paragraph associated with your single NSLayoutManager. The trick is
    you'd need to have a way to break your content up logically into
    these containers. I can think of two options:

    1. Have your NSTextStorage play along by maintaining a series of
    artificial container/page breaks in the text stream wherever you want
    to separate your content into another view.

    2. Resize your NSTextContainers to exactly fit the content they need
    to show. This doesn't sound appealing, since you'd have to resize
    each container as each edit/layout cycle finishes.

    ~Martin
  • Martin,

    >> 1. First is it possible to subclass or tell NSLayoutManger to only
    >> work with a specific range and just layout that range in it's
    >> associated NSTextStorage?
    >
    > This definitely isn't possible with the current public
    > NSLayoutManager API. I've never tried anything like you want, but
    > if you did dig into the private methods, I bet it would be a huge
    > effort (or impossible) and much frustration. All the NSTextStorage
    > APIs you need are public, so I'd stick with what you have.
    >
    >> 2. Or if the above isn't possible is it possible to tell a
    >> NSTextView to just draw and edit a subrange of it's text and
    >> ignore the rest?
    >
    > What you want isn't directly possible, but you could always
    > construct a series of NSTextContainers to accomplish what you like.
    > Basically you would just assign the NSTextView the container for
    > the Nth paragraph associated with your single NSLayoutManager. The
    > trick is you'd need to have a way to break your content up
    > logically into these containers. I can think of two options:
    >
    > 1. Have your NSTextStorage play along by maintaining a series of
    > artificial container/page breaks in the text stream wherever you
    > want to separate your content into another view.
    >
    > 2. Resize your NSTextContainers to exactly fit the content they
    > need to show. This doesn't sound appealing, since you'd have to
    > resize each container as each edit/layout cycle finishes.

    Thanks for your responses. My reading of the api came up with similar
    conclusions, I was just hoping that I was missing something and that
    there was a cleaner way.

    Thanks,
    Jesse
  • On 14.09.2007, at 14:28, Jesse Grosjean wrote:
    > I have a text view, and I want it to just display and edit a
    > subrange of it's associated NSTextStorage. For example lets say my
    > text storage has 10 paragraphs, but I just want my NSTextView to
    > display and edit one of them. I also need the solution to scale to
    > multiple NSTextViews, so for example one view will be viewing
    > paragraphs 2-3, while another might be viewing paragraphs 3-4.
    >
    > I'm wondering what the best way to approach this problem is?

      Have you thought about just creating a substring of the full text
    view and editing that? Syncing the two ranges by copying back and
    forth when either is edited should be less trouble than trying to
    share a text storage and keeping it restricted to a particular range.

      Though I think someone on this list once asked about sharing the
    same text storage between several NSTextViews and got it solved ...
    maybe you could let the user view, but not edit, the other ranges?
    You could for example apply a custom (temporary?) style attribute to
    the characters that tells you which view can edit a particular piece
    of text, and then use shouldChangeTextInRange: to enforce that. Would
    that perhaps work better?

      Just listing alternatives, as it sounds like one *should*
    conceptually be able to do this on the NSTextxxx level.

    Cheers,
    -- M. Uli Kusterer
    http://www.zathras.de
  • > Have you thought about just creating a substring of the full text
    > view and editing that? Syncing the two ranges by copying back and
    > forth when either is edited should be less trouble than trying to
    > share a text storage and keeping it restricted to a particular range.

    That's pretty much what I'm doing now, and from the feedback that I'm
    hearing I think I'll stick with that. The problem with this approach
    is that it's hard to make the synching part work well with undo. Once
    you get the details right you'll still be stuck with the problem of
    undo's not being coalesced, so you'll get an undo on the stack for
    every character typed.

    > Though I think someone on this list once asked about sharing the
    > same text storage between several NSTextViews and got it solved ...

    Yes, that's pretty easy and well supported and documented in the
    cocoa text docs. Just add a new NSLayoutManger/textcontainer/textview
    to the text storage for each separate NSTextView that you want.

    > maybe you could let the user view, but not edit, the other ranges?
    > You could for example apply a custom (temporary?) style attribute
    > to the characters that tells you which view can edit a particular
    > piece of text, and then use shouldChangeTextInRange: to enforce
    > that. Would that perhaps work better?

    Unfortunately I need to allow people to edit the subranges.

    Anyway thanks for everyone's feedback. My current solution seems to
    be working, I was just hoping that there was some trick in
    NSLayoutManager that would make my code simpler.

    Jesse
previous month september 2007 next month
MTWTFSS
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Go to today