This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

Bug 198657 - APIs to work with Modes (implement jVi window split/move/... commands)
Summary: APIs to work with Modes (implement jVi window split/move/... commands)
Status: NEW
Alias: None
Product: platform
Classification: Unclassified
Component: Window System (show other bugs)
Version: 7.0
Hardware: PC All
: P3 normal with 1 vote (vote)
Assignee: Stanislav Aubrecht
URL:
Keywords:
Depends on: 198748
Blocks: 179047
  Show dependency tree
 
Reported: 2011-05-16 21:26 UTC by err
Modified: 2014-12-10 17:22 UTC (History)
7 users (show)

See Also:
Issue Type: ENHANCEMENT
Exception Reporter:


Attachments
Sample usage of dockInto followed by open and requestActive which works. (3.78 KB, text/plain)
2011-05-19 16:03 UTC, Jaroslav Tulach
Details
add adjust mode API (first cut) (13.49 KB, patch)
2011-05-21 23:41 UTC, err
Details | Diff
updated patch with SplitSubModel.adjustSizes (13.88 KB, patch)
2011-05-22 20:53 UTC, err
Details | Diff
current jVi NB reflection hooks interface (2.38 KB, text/plain)
2011-12-15 04:12 UTC, err
Details

Note You need to log in before you can comment on or make changes to this bug.
Description err 2011-05-16 21:26:20 UTC
To implement a subset of jVi window manipulation commands, following is needed
(1) move an Editor to a different Mode
(2) Create a new mode and put tcs into it (set size of split)
(3) Adjust size of mode (move splitter)
(4) mode's hierarchical and geometric relationships

I'd be satisfied with friend only API (as long as jVi can be a friend). If this has a good chance of getting checked in, I'll work on it. Some of the first issues are:
(a) long term goals, whose the target, 1-4 above is jVi use case
(b) friend only?
(c) how much to expose; extensive or precise and limited.
(d) there's Bug 96323 and Bug 135385 which should be considered.

I've implemented (1) through reflection (friend access not enough):
    meth_userDroppedTopComponents().invoke(central, mode, tcs);
BTW, Mode.dockInto doesn't work with editors since it closes the TopComponent.

I'm currently working around (4) by traversing a window's component hierarchy and building a tree (use it for commands that change focus to neighboring editors); here's some debug output to give you an idea:

WindowTree for MyNode@cc04
    split:  MultiSplitPane LeftRight
        editor: QuietEditorPane Edi1 mode=anonymousMode_1 isEdMode=true
        split:  MultiSplitPane TopBottom
            editor: QuietEditorPane Hookup.java mode=anonymousMode_3 isEdMode=true
            editor: QuietEditorPane Main.java mode=anonymousMode_4 isEdMode=true
            editor: QuietEditorPane Foo1 mode=editor isEdMode=true
Comment 1 err 2011-05-18 00:53:59 UTC
Here's a proposal, with behavioral details below.

Methods:
    boolean moveInto(Mode m, TopComponent[], index)
    Mode createSplit   (Mode m, direction, TopComponent[], constraints)
    Mode createNeighbor(Mode m, direction, TopComponent[], constraints)

    ? adjusting the size of a mode

    List<Mode> getNeighbors(Mode m, direction, kind)
    boolean touches(Mode mA, Mode mB)
    Rectangle getBounds(Mode m)

The methods getNeighbors and touches only operate within a
swing Window.  No "separated" relationships.

===
=== Details
===

Moving a tc from one mode to another

    boolean moveInto(Mode m, TopComponent[], index)
        optional index

    The current Mode.dockInto(tc) closes the TC, so doesn't work with
    editors.


Creating a new mode.

    Create and populate a new mode which touches the param Mode.

    Mode createSplit   (Mode m, direction, TopComponent[], constraints)
    Mode createNeighbor(Mode m, direction, TopComponent[], constraints)

        new_mode = createNeighbor(m1, NORTH, ...)
            +------------+--------------+
            |         new_mode          |
            +------------+--------------+
            |    m1      |     m2       |
            +------------+--------------+

    createSplit and createNeighbor do the same thing
    when m's container's orientation is the same as the direction.

    Want to avoid complex constraints. Possibilities include
        - Modes in split pane have equal height/width in direction.
        - Specify percentage for new mode in direction.
        - Specify weights for new and existing modes in splitter.


Adjusting the size of a mode and/or moving a splitter

    I'm having trouble with this one. Some approaches:
        - Move a splitter a number of pixels/percentage in direction.
        - Specify new weights to apply to a multi split pane.


Querying geometric info about a mode.

    List<Mode> getNeighbors(Mode m, direction, kind)  // may be empty list
        kind is an optional convenience, like kind == editor

                +------------+--------------+--------------+
                |    m1      |     m2       |     m3       |
                +------------+--------------+--------------+
                |            m4         |       m5         |
                +------------+-----------------------------+

            getNeighbors(m1, SOUTH) --> (m4, m5)
            getNeighbors(m4, NORTH) --> (m1, m2, m3)

    boolean touches(Mode mA, Mode mB)

            touches(m1, m4) --> true
            touches(m1, m5) --> false

    Rectangle getBounds(Mode m)
        Returns bounds within swing Window

        There is currently Mode.getBounds(), but that returns (0,0,0,0).
        If its ok, just fix that.
Comment 2 Jaroslav Tulach 2011-05-19 16:02:52 UTC
(In reply to comment #1)
>     The current Mode.dockInto(tc) closes the TC, so doesn't work with
>     editors.

That sound like a bug to me. It was never the case neither intention in the original (3.1, 3.2) implementation of the API. Imho you can report a bug to leave the component open. Anyway there is an easy workaround around this, so I don't believe any new API for this is justified.
Comment 3 Jaroslav Tulach 2011-05-19 16:03:37 UTC
Created attachment 108397 [details]
Sample usage of dockInto followed by open and requestActive which works.
Comment 4 err 2011-05-19 16:10:38 UTC
(In reply to comment #3)
> Sample usage of dockInto followed by open and requestActive which works.

Some earlier investigations indicated that this probably wouldn't work for editors. At least I know of no situation where a closed editor is later re-opened.

I'll investigate further. (And file that bug you mentioned)
Comment 5 err 2011-05-20 01:35:01 UTC
Changes:    - assume mode.dockInto() is fixed for the close issues
            - method names
            - concrete proprosal for constraints/sizes
            - remove "touches()" method (calculate based on Mode.getBounds())
            - questions/issues about mode.getBounds

              (was createSplit)
Mode WindowManager.createModeOnSide(Mode mode,
                                    String side,
                                    TopComonent[] tcs,
                                    WeightCalculator wc)

              (was createNeighbor)
Mode WindowManager.createModeAround(Mode mode,
                                    String side,
                                    TopComonent[] tcs,
                                    WeightCalculator wc)
    (should this be ...AroundEditor? I'm thinking if param mode
    not isEditorMode, then return null)

                    (was getNeighbors)
List<Mode> WindowManager.findModes(Mode mode, String side)

boolean WindowManager.adjustSizes(Mode mode, WeightCalculator wc)

- createModeOnSide, createModeAround and findModes return null
  if there's a problem.
- side could be an enum instead of a String
- don't strictly need the WeightCalculator param to createModeOnSide
  and createModeAround; could require use of adjustSizes after create,
  though that is probably less efficient.
  Note: it is *much* simpler to not have this.

WeightCalculator
------------------
Parameter to createModeOnSide, createModeAround and adjustSizes

This approach exposes almost nothing and can expand if/when there are
additional requirements. No knowledge of splitter siblings needed beforehand.
Note: the param can be null and then default sizing takes place.
Note: some of the weights may be for a SplitPane.

The WindowManager user examines existing weights through SiblingState.
The List<Double> from SiblingState.getWeights() can be modified and returned;
the length can be not changed.

    interface WeightCalculator {
        List<Double> getWeights(SiblingState currentState);
    }

    interface SiblingState {
        Orientation getOrientation(); // enum or int like HORIZONTAL_SPLIT
        int getTargetIndex(); // new mode for create... or mode to adjust
        List<Double> getWeights();
                // Could add following someday, not needed today (by jVi)
                // List<ModelElementInfo> xxx; // e.g. mode, splitPane ...
    }

getBounds() issues
------------------
I'm guessing that to fix Mode.getBounds() the core.windows.view logic
needs to update the model as appropriate. But model.setModeBounds is
only invoked from Central. I think there's something going on I don't
understand.

Model issues
------------------
- I could not find any core.windows.Model tests.
  This argues for not having the WeightCalculator param to
  createModeOnSide and createModeAround.  adjustSizes() can be
  implemented (I'm guessing) without changing any existing code.
- findModes(Mode, Side) is a new Model traversal algorithm, but
  implementation should not change any existing code.
Comment 6 err 2011-05-20 01:46:24 UTC
Dave or Mila. Do you know if an editor TopComponent can be closed and then opened? See also Bug 198748.

(In reply to comment #2)
(In reply to comment #3)
> > there is an easy workaround around this
> > Sample usage of dockInto followed by open and requestActive which works.
> 
> Some earlier investigations indicated that this probably wouldn't work for
> editors. At least I know of no situation where a closed editor is later
> re-opened.
Comment 7 err 2011-05-21 23:41:21 UTC
Created attachment 108437 [details]
add adjust mode API (first cut)

This patch adds API methods
    WindowManager.addModeOnSide
    WindowManager.addModeAround
    WindowManager.adjustSizes
and interfaces
    WindowManager.WeightCalculator
    WindowManager.SiblingState

There are some questions in comments in WindowManager.
Tested by usage. Guidance on what/how to test needed.


Though I believe some geometric API is needed, findModes is discarded from the
proposal. To properly adjust weights, the size of the Mode and the size of the splitter in which the mode resides are needed. This information could be provided as part of SiblingState and getting Mode.getBouds to work.
Comment 8 err 2011-05-22 20:53:59 UTC
Created attachment 108443 [details]
updated patch with SplitSubModel.adjustSizes

The patch has a bug, SplitSubModel.adjustSizes should be using getVisibleChildren and I've added a few more checks to that method.

Updated patch (only SplitSubModel.adjustSizes changed)
Comment 9 Stanislav Aubrecht 2011-05-25 08:31:53 UTC
i'm not very happy about this because this api change would expose a lot of things that are considered an implementation detail in the netbeans window system.
there might be other window system implementations that don't use any splits at all, e.g. they might be based on a plain JTabbedPane...

if my understanding is correct then the main driver for these changes is the ability to programmatically split an editor window and adjust split position if needed. and the proposed solution is to clone the editor window and add the clone to a new editor mode. is that correct?

we're actually planning to introduce 'split editor' feature in netbeans 7.1
then you'll be able to create a split hierarchy within a single editor window tab. the same way as e.g. JDeveloper does it. wouldn't that cover your use case?
Comment 10 err 2011-07-05 17:37:42 UTC
(In reply to comment #9)
> i'm not very happy about this because this api change would expose a
> lot of things that are considered an implementation detail in the
> netbeans window system.  there might be other window system
> implementations that don't use any splits at all, e.g. they might be
> based on a plain JTabbedPane...

Any or all of the proposed capabilities, which are generic in nature and common, could be considered optional. They do nothing if an implementation doesn't want to support them. Some technique to advertise what capabilities are supported could be considered.

A compromise would be to expose the capabilities as friend only.

BTW, the attachment is meant as a way to get a discussion going; if there's a better way to have this discussion, please let me know.

> if my understanding is correct then the main driver for these changes
> is the ability to programmatically split an editor window and adjust
> split position if needed.  and the proposed solution is to clone the
> editor window and add the clone to a new editor mode. is that correct?

Yes. Also moving tabs between editor areas. An important aspect is viewing multiple files at the same time with commands to move focus between them.

> we're actually planning to introduce 'split editor' feature in netbeans
> 7.1 then you'll be able to create a split hierarchy within a single editor
> window tab. the same way as e.g. JDeveloper does it.

I'm confused as to why a new capability is being added when existing capabilities handle the requirement; seems like it will be generally confusing. But that's a different issue...

After the split can you show different files in the split-areas? Are there any prelim descriptions of the new feature to look at? (I'm unfamiler with what JDeveloper does. The original JBuilder (JDevelopers parent and jVi's original platform) didn't have that).

> wouldn't that cover your use case?

Not entirely. jVi is not intended to be a standalone editor. The idea is to give vi/vim semantics to the environment; in this case NetBeans. If creating multiple editor modes, and moving editors between them, continues to be a NetBeans feature, then jVi wants to support it.

BTW, the nbvi-1.4.2 release supports all the major vim window split/resize/move commands using reflection, if you want to see them in action. The setting of initial size after a split and the resize are an ugly hack, but it all works pretty well.
Comment 11 err 2011-11-28 19:02:23 UTC
saubrecht,

could you comment on comment 10 ?
Comment 12 Stanislav Aubrecht 2011-12-12 15:41:11 UTC
there are new actions in nb 7.1:
- New Document Tab Group
- Size Group

the actions could be extended to accept the desired side (when creating a new split) or the desired size (when resizing a mode). how would that work for you?

and how about having implementation dependency on core.windows module? then you have enough power to do almost anything:)
Comment 13 err 2011-12-15 04:11:35 UTC
(In reply to comment #12)

FYI, I've attached the interface that the NB dependent window code uses to poke into the window system.

> there are new actions in nb 7.1:
> - New Document Tab Group
> - Size Group

Where's the code for these?

BTW, the jVi :toggle command does the new minimize/restore actions on the output mode by. No NB API; requires reflection.

> the actions could be extended to accept the desired side (when creating
> a new split)

jVi uses both addModeOnSide and addModeAround. I can describe (remember) the semantics if you are interested.

> or the desired size (when resizing a mode). how would that
> work for you?

Size is tricky; must be able to obtain the current size for an editor to split and be able to get (deduce) the border and/or toolbar. vim has rules and options for determining how other windows might change size when doing a split. Notice that the current interface to set weights is

    void setWeights(Component splitter, double[] weights);

> and how about having implementation dependency on core.windows module?
> then you have enough power to do almost anything:)

Problem is maintenance and support. For example, the current binary release runs on both nb7.0 and nb7.1; that is likely impossible with ImplDep. And thinking about how frequently module versions change during devlopment... If what I needed was accessible as "friend", as already mentioned in the description, that would be ok. I haven't digested Jesse's recent "Package stability proposal", so in the future something like what you are talking about might make sense.

If there were support for versioning in the Update Center, that might reduce the problems.

In addition, the vim commands to move the cursor to a neighboring window need to know the geometric relationship of things. jVi gets this info, and builds a tree, by traversing NBs swing hierarchy to determine the JEditorPane/splitter relationships.

It would be wonderful to have a way to do this stuff without reflection. Sounds like a lot of work.
Comment 14 err 2011-12-15 04:12:51 UTC
Created attachment 114203 [details]
current jVi NB reflection hooks interface
Comment 15 oliverrettig 2013-05-23 07:53:23 UTC
My usecase is an editor window with fix aspect ratio. This is needed for some medical/scientific applications where the editor window show a report which should look identical to a print version to a fix paper size.

To to able to implement this I need a "mode api" to control the split.
Comment 16 err 2014-12-10 17:22:54 UTC
After the discussion started by jtulach last month in Bug 135385 (about APIs and issues just hanging around), I'm assigning this to saubrecht for resolution.

This is probably a won't fix. I don't perceive any interest for discussion of comments/questions. The NB-dev bottom line seems to be stated in comment #9

>   expose a lot of things that are considered an implementation detail
>   in the netbeans window system

The jVi window commands are pretty complete and implemented through reflection. jVi is primarily in maintenance mode. If the internals of the windowing system don't change much...