<html>
    <head>
        <meta name="viewport" content="width=device-width" />
        <base href="http://wiki.javaforum.hu" />
        <style type="text/css">
    body, #email-content, #email-content-inner { font-family: Arial,FreeSans,Helvetica,sans-serif; }
    body, p, blockquote, pre, code, td, th, li, dt, dd { font-size: 13px; }
    small { font-size: 11px; }

    body { width:100% !important; -webkit-font-smoothing: antialiased; }

    body,
    #email-wrapper { background-color: #f0f0f0; }
    #email-wrapper-inner { padding: 20px; text-align: center; }
    #email-content-inner { background-color: #fff; border: 1px solid #bbb; color: $menuTxtColour; padding:20px; text-align:left; }
    #email-wrapper-inner > table { width: 100%; }
    #email-wrapper-inner.thin > table { margin: 0 auto; width: 50%; }
    #email-footer { padding: 0 16px 32px 16px; margin: 0; }

    .email-indent { margin: 8px 0 16px 0; }
    .email-comment { margin: 0 0 0 56px; }

    #email-title-avatar { text-align: left; vertical-align: top; width: 56px; }
    #email-title-flavor { margin: 0; padding: 0 0 4px 0; }
    #email-title-heading { font-size: 16px; line-height: 20px; min-height: 20px; margin: 0; padding: 0; }
    #email-title .icon { border: 0; padding: 0 2px 0 0; text-align: left; }

    #email-actions { border-top: 1px solid #bbb; color: #505050; margin: 8px 0 0 0; padding: 0; }
    #email-actions td { padding-top: 8px; }
    #email-actions .left { max-width: 45%; text-align: left; }
    #email-actions .right { text-align: right; }
    .email-reply-divider { border-top: 1px solid #bbb; color: #505050; margin: 32px 0 8px 0; padding: 8px 0; }
    .email-section-title { border-bottom: 1px solid #bbb; margin: 8px 0; padding: 8px 0 0 0; }

    .email-metadata { color: #505050; }

    a { color: #326ca6; text-decoration: none; }
    a:hover { color: #336ca6; text-decoration: underline; }
    a:active {color: #326ca6; }

    a.email-footer-link { color: #505050; font-size: 11px; }

    .email-item-list { list-style: none; margin: 4px 0; padding-left: 0; }
    .email-item-list li { list-style: none; margin: 0; padding: 4px 0; }
    .email-list-divider { color: #505050; padding: 0 0.35em; }

    .avatar { -ms-interpolation-mode: bicubic; }
    .avatar-link { margin: 2px; }

    .tableview th { border-bottom: 1px solid #69C; font-weight: bold; text-align: left; }
    .tableview td { border-bottom: 1px solid #bbbbbb; text-align: left; padding: 4px 16px 4px 0; }

    .aui-message {  margin: 1em 0; padding: 8px; }
    .aui-message.info { background-color: #e0f0ff; border: 1px solid #9eb6d4; }
    .aui-message.success { background-color: #ddfade; border: 1px solid #93c49f; }
    .aui-message.error,
    .aui-message.removed { background-color: #ffe7e7; border: 1px solid #df9898; color: #000; }

    .call-to-action-table { margin: 10px 1px 1px 1px;}
    .call-to-action-container { text-align: right; padding: 5px 20px; border: 1px solid #326396;  background-color: #6495C7; border-radius: 3px;}
    .call-to-action-container a.call-to-action-button { background-color: #6495C7; font-size: 15pt; line-height: 1; padding: 0; margin: 0; color: #fff; }

            @media handheld, only screen and (max-device-width: 480px) {
        div, a, p, td, th, li, dt, dd { -webkit-text-size-adjust: auto; }
        small, small a { -webkit-text-size-adjust: 90%; }

        td[id=email-wrapper-inner] { padding: 2px !important; }
        td[id=email-content-inner] { padding: 8px !important; }
        td[id="email-wrapper-inner"][class="thin"] > table { text-align: left !important; width: 100% !important; }
        td[id=email-footer] { padding: 8px 12px !important; }
        div[class=email-indent] { margin: 8px 0px !important; }
        div[class=email-comment] { margin: 0 !important; }

        p[id=email-title-flavor] a { display: block; } /* puts the username and the action on separate lines */
        p[id=email-permalink] { padding: 4px 0 0 0 !important; }

        table[id=email-actions] td { padding-top: 0 !important; }
        table[id=email-actions] td.right { text-align: right !important; }
        table[id=email-actions] .email-list-item { display: block; margin: 1em 0 !important; word-wrap: normal !important; }
        span[class=email-list-divider] { display: none; }
    }

        </style>
    </head>
    <body style="font-family: Arial, FreeSans, Helvetica, sans-serif; font-size: 13px; width: 100%; -webkit-font-smoothing: antialiased; background-color: #f0f0f0">
        <table id="email-wrapper" width="100%" cellspacing="0" cellpadding="0" border="0" style="background-color: #f0f0f0">
            <tbody>
                <tr valign="middle">
                    <td id="email-wrapper-inner" style="font-size: 13px; padding: 20px; text-align: center">
                        <table id="email-content" cellspacing="0" cellpadding="0" border="0" style="font-family: Arial, FreeSans, Helvetica, sans-serif; width: 100%">
                            <tbody>
                                <tr valign="top">
                                    <td id="email-content-inner" align="left" style="font-family: Arial, FreeSans, Helvetica, sans-serif; font-size: 13px; background-color: #fff; border: 1px solid #bbb; padding: 20px; text-align: left">
                                        <table id="email-title" cellpadding="0" cellspacing="0" border="0" width="100%">
                                            <tbody>
                                                <tr>
                                                    <td id="email-title-avatar" rowspan="2" style="font-size: 13px; text-align: left; vertical-align: top; width: 56px"> <img class="avatar" src="cid:avatar_60b83424488b05c3771e4bb43c268a2b" border="0" height="48" width="48" style="-ms-interpolation-mode: bicubic" /> </td>
                                                    <td valign="top" style="font-size: 13px">
                                                        <div id="email-title-flavor" class="email-metadata" style="margin: 0; padding: 0 0 4px 0; color: #505050">
                                                            <a href="http://wiki.javaforum.hu/display/~ivanhu" style="color:#326ca6;text-decoration:none;; color: #326ca6; text-decoration: none">Ketler Istv&aacute;n</a> wrote a blog post:
                                                        </div> </td>
                                                </tr>
                                                <tr>
                                                    <td valign="top" style="font-size: 13px"> <h2 id="email-title-heading" style="font-size: 16px; line-height: 20px; min-height: 20px; margin: 0; padding: 0"> <a href="http://wiki.javaforum.hu/pages/viewpage.action?pageId=30998704" style="color: #326ca6; text-decoration: none"> <img class="icon" src="cid:blogpost-icon" alt="" style="border: 0; padding: 0 2px 0 0; text-align: left" /> <strong style="font-size:16px;line-height:20px;vertical-align:top;">JavaFX Adventures part 3 - Design Considerations (+GridPane)</strong> </a> </h2> </td>
                                                </tr>
                                            </tbody>
                                        </table>
                                        <div class="email-indent" style="margin: 8px 0 16px 0">
                                            <div class="email-page">
                                                <p style="font-size: 13px">Due to the fact that the custom component should host a visual information much larger than it is possible to show on most displays, therefore it is just evident that a kind of scroll pane be used. The already existing Swing counterpart is a scroll pane, with a column header (that's the date and time information) and a row header (those are the resources). So first I have checked the FX ScrollPane (javafx.scene.control.ScrollPane). It turned out soon that the FX version has no headers - neither column, nor row header. There must be a reason why, but I don't really care. I decided at the very beginning that I'll never criticise the JavaFX - I'll just try to use it. That's just a fact that there are no headers of the FX ScrollPane, so I have to consider another solution.</p>
                                                <div class="panelMacro">
                                                    <table class="infoMacro">
                                                        <colgroup>
                                                            <col width="24" />
                                                            <col />
                                                        </colgroup>
                                                        <tbody>
                                                            <tr>
                                                                <td valign="top" style="font-size: 13px"><img src="/images/icons/emoticons/information.png" width="16" height="16" align="absmiddle" alt="" border="0" /></td>
                                                                <td style="font-size: 13px"><b>JavaFX limitation</b> <br /> <p style="font-size: 13px">The JavaFX ScrollPane has no column or row header, it maintains only the viewport (called &quot;content&quot;), and the two scroll bars (both are optional, and may appear only on demand). The FX ScrollPane is not a panel at all - it is a specialized control instead. Therefore, its getChildren() method - which is intended to add components to a parent - is not visible, and provides a dedicated method (setContent) to add the only available child - the viewport.</p> </td>
                                                            </tr>
                                                        </tbody>
                                                    </table>
                                                </div>
                                                <p style="font-size: 13px">Creating a compound window and using it as the content of the scroll pane is not a real solution. Theoretically, I might be possible that upon scrolling, the content of this compound window be adjusted so that the header parts remain fixed (always shown). However, that doesn't really seem to be a reliable, bulletproof solution, so I had to consider other approaches. Soon I turned to the GridPane (javafx.scene.layout.GridPane). It lays out its children in a Grid, by using rows and columns. The width of the columns and the height of the rows might differ from each other. It is easy to achieve that all components within the same column be sized to have the same width, and within the same row to have the same height. In fact, that's the default behaviour. So I might have the following layout of this GridPane:</p>
                                                <div class="table-wrap">
                                                    <table class="confluenceTable" style="border-collapse: collapse; border: 1px solid #ddd;">
                                                        <tbody>
                                                            <tr>
                                                                <th class="nohighlight confluenceTh" style="border: 1px solid #DDD; padding: 5px 7px; min-width: 0.6em; text-align: left; vertical-align: top;background-color: #F0F0F0; font-weight: bold;; font-size: 13px"><span style="color: rgb(0,0,255);"><em>Header of the</em></span> <br /> <span style="color: rgb(0,0,255);"><em>Row Header</em></span></th>
                                                                <th class="nohighlight confluenceTh" style="border: 1px solid #DDD; padding: 5px 7px; min-width: 0.6em; text-align: left; vertical-align: top;background-color: #F0F0F0; font-weight: bold;; font-size: 13px"><span style="color: rgb(0,0,255);"><em>The Column Header - that is, the Timeline view</em></span></th>
                                                                <th class="nohighlight confluenceTh" style="border: 1px solid #DDD; padding: 5px 7px; min-width: 0.6em; text-align: left; vertical-align: top;background-color: #F0F0F0; font-weight: bold;; font-size: 13px"><span style="color: rgb(0,0,255);"><em>Header of the Row Footer</em></span></th>
                                                                <th class="nohighlight confluenceTh" style="border: 1px solid #DDD; padding: 5px 7px; min-width: 0.6em; text-align: left; vertical-align: top;background-color: #F0F0F0; font-weight: bold;; font-size: 13px"><span style="color: rgb(0,0,255);"><em>Empty</em></span></th>
                                                            </tr>
                                                            <tr>
                                                                <td class="confluenceTd" style="border: 1px solid #DDD; padding: 5px 7px; min-width: 0.6em; text-align: left; vertical-align: top;; font-size: 13px"><span style="color: rgb(0,0,255);"><em>The Row Header - that is,</em></span> <br /> <span style="color: rgb(0,0,255);"><em>the resources the activities</em></span> <br /> <span style="color: rgb(0,0,255);"><em>are assigned to.</em></span></td>
                                                                <td class="confluenceTd" style="border: 1px solid #DDD; padding: 5px 7px; min-width: 0.6em; text-align: left; vertical-align: top;; font-size: 13px"><span style="color: rgb(0,0,255);"><em>The activities and the relations between the activities.</em></span> <br /> <span style="color: rgb(0,0,255);"><em> The activities start at a specific point of time, end later,</em></span> <br /> <span style="color: rgb(0,0,255);"><em> and they belong to resources.</em></span></td>
                                                                <td class="confluenceTd" style="border: 1px solid #DDD; padding: 5px 7px; min-width: 0.6em; text-align: left; vertical-align: top;; font-size: 13px"><span style="color: rgb(0,0,255);"><em>The Row Footer - that is,</em></span> <br /> <span style="color: rgb(0,0,255);"><em>the resources the activities</em></span> <br /> <span style="color: rgb(0,0,255);"><em>are assigned to.</em></span></td>
                                                                <td class="confluenceTd" style="border: 1px solid #DDD; padding: 5px 7px; min-width: 0.6em; text-align: left; vertical-align: top;; font-size: 13px"><span style="color: rgb(0,0,255);"><em>Main vertical</em></span> <br /> <span style="color: rgb(0,0,255);"><em>scroll bar</em></span></td>
                                                            </tr>
                                                            <tr>
                                                                <td class="confluenceTd" style="border: 1px solid #DDD; padding: 5px 7px; min-width: 0.6em; text-align: left; vertical-align: top;; font-size: 13px"><span style="color: rgb(0,0,255);"><em>Horitonzal scroll bar of the</em></span> <br /> <span style="color: rgb(0,0,255);"><em>Row Header</em></span></td>
                                                                <td class="confluenceTd" style="border: 1px solid #DDD; padding: 5px 7px; min-width: 0.6em; text-align: left; vertical-align: top;; font-size: 13px"><span style="color: rgb(0,0,255);"><em>Main horizontal scroll bar </em></span></td>
                                                                <td class="confluenceTd" style="border: 1px solid #DDD; padding: 5px 7px; min-width: 0.6em; text-align: left; vertical-align: top;; font-size: 13px"><span style="color: rgb(0,0,255);"><em>Horizontal scroll bar of the</em></span> <br /> <span style="color: rgb(0,0,255);"><em>Row Footer</em></span></td>
                                                                <td class="confluenceTd" style="border: 1px solid #DDD; padding: 5px 7px; min-width: 0.6em; text-align: left; vertical-align: top;; font-size: 13px"><span style="color: rgb(0,0,255);"><em>Empty</em></span></td>
                                                            </tr>
                                                        </tbody>
                                                    </table>
                                                </div>
                                                <p style="font-size: 13px">Therefore, the resources might be either repeated, or being able to display different set of information on the right side - that's the &quot;Row Footer&quot;. It is also shown that the resource view might be wider than the available space - hence the horizontal scroll bars for the row header and footer. This is possible, because the optional header of the row header or the header of the row footer are both supposed to have the same width than their corresponding resource view. However, the height of the timeline view must be fixed, and it cannot be scrolled - that's because the height of the header's and footer's header might have different height than the timeline view has.</p>
                                                <p style="font-size: 13px">There are rules to keep too. The horizontal scroll bar of the Row Header must control the scrolling of the Row Header, and the Header of the Row Header - those two must be synchronized when scrolled. Similarly, the horitontal scroll bar of the Row Footer must control the scrolling of the Row Footer, and the Header of the Row Footer - their horizontal scrolling is again synchronized. The main horizontal scroll bar must control the horizontal scrolling of the main viewport, and the time line simultaneously. The main vertical scroll bar must control the vertical scroll of the Row Header, the Main Viewport, and the Row Footer. Due to the fact that it is possible to scroll by using alternative input methods (mouse wheel, touchpad edges, etc.), therefore it must be ensured that whenever a view scrolls, the corresponding associated other views should be scrolled just the same.</p>
                                                <p style="font-size: 13px">Conclusion: the custom component is a grid pane, with six ScrollPanes and four ScrollBars added. The height of the first row should come from the Timeline view (it is accepted to introduce a limitation that no header might be any taller).The visible and the full width of the Left Resource View should come from that view (the visible width is the width of the first column). The visible and the full width of the Right Resource View should come from that view (and the visible width is the width of the third column). The visible and full width of the second column should come from the main viewport, which is&nbsp; the Activity View. The visible and full height of the second row should come from the Left Resource Pane. It will be a recommendation that both the Activity View and the Right Resource View have the same full height - the custom component might or might not enforce this rule, it could be decided later. The width and height of the scroll bars shouldn't be set explicitely, just let it be set automatically.</p>
                                                <div class="code panel" style="border-width: 1px;">
                                                    <div class="codeHeader panelHeader" style="border-bottom-width: 1px;">
                                                        <b>Controlling the rows and columns of a GridPane</b>
                                                    </div>
                                                    <div class="codeContent panelContent">
                                                        <pre class="theme: Default; brush: java; collapse: true; gutter: true" style="font-size:12px;; font-size: 13px">    // *******************
    // Set the column constraints

    // leftWidth and all those are the preset widths coming from the corresponding models according to the rules described above

    ColumnConstraints cc1 = new ColumnConstraints();
    cc1.setPrefWidth(leftWidth);
    cc1.setMaxWidth(leftWidth);
    cc1.setMinWidth(leftWidth);
    cc1.setHgrow(Priority.NEVER);

    ColumnConstraints cc3 = ColumnConstraintsBuilder
            .create()
            .hgrow(Priority.NEVER)
            .minWidth(rightWidth)
            .maxWidth(rightWidth)
            .prefWidth(rightWidth)
            .build();

        // Define the other column constraints similarly

    myCustomGripPane.getColumnConstraints().addAll(cc1, cc2, cc3, cc4);

    // *******************
    // Set the row constraints - it's very similar

    RowConstraints rc2 = new RowConstraints();
    rc2.setPrefHeight(height * visibleNumber);
    rc2.setMaxHeight(height * totalNumber);
    rc2.setVgrow(Priority.ALWAYS);

    // Define the other row constraints similarly

    myCustomGridPane.getRowConstraints().addAll(rc1, rc2, rc3);

    // *******************
    // Add the cells

    myCustomGridPane.add(rowheaderHeader, 0, 0);    // row, column
    myCustomGridPane.add(timelineView, 1, 0);
    // and so on

</pre>
                                                    </div>
                                                </div>
                                                <p style="font-size: 13px">Now I have the general layout. The next question is, what should be the content of those six scroll panes. The constraints are that although the resources forming a kind of list, which might be represented as a table, but the timeline is not really a horizontally laid out table (unless I am prepared to use a table with hundreds of thousands of columns). That's because the resolution of the time line is one minute, but the total length might be one full year, thus I have 366*24*60 columns - that's 527,040 columns. That's not very practical to use a table like that. Also, considering that this general tool must be able to support logistics, and one resource may have even more activities on a daily basis, therefore one row might contain few hundred activities. Adding the fact that there might be several hundreds of resources, it doesn't seem to be adequate to use Controls as the representation of activities. So having panels as contents of the scroll panes, and adding controls to those panels is not the way to go. Having many (even hundreds of) thousands of controls on a view is definitely not the way to go - usually, the controls are resources of the underlying system. I do not have the urge to check this assumption currently. I will give it a try later; perhaps Java FX uses the controls differently than all those GUIs I met before.</p>
                                                <p style="font-size: 13px">So for now, the decision I made was to use Canvases, and draw upon those Canvases directly. Then the resources, the timeline, and the activities are all just painted (rendered) shapes like rectangles. Therefore, the adventure will continue with using the Canvas.</p>
                                                <p style="font-size: 13px">Previous pages:</p>
                                                <p style="font-size: 13px"> <a href="http://wiki.javaforum.hu/display/~ivanhu/2013/01/27/JavaFX+Adventures+part+1+-+Intro" style="color: #326ca6; text-decoration: none">part 1 - Intro</a> </p>
                                                <p style="font-size: 13px"> <a href="http://wiki.javaforum.hu/display/~ivanhu/2013/01/27/JavaFX+Adventures+part+2+-+Application+frame" style="color: #326ca6; text-decoration: none">part 2 - Application frame</a> </p>
                                                <p style="font-size: 13px">Next pages:</p>
                                                <p style="font-size: 13px">part 4 - How to use Canvas</p>
                                            </div>
                                        </div>
                                        <table id="email-actions" class="email-metadata" cellspacing="0" cellpadding="0" border="0" width="100%" style="border-top: 1px solid #bbb; color: #505050; margin: 8px 0 0 0; padding: 0; color: #505050">
                                            <tbody>
                                                <tr>
                                                    <td class="left" valign="top" style="font-size: 13px; padding-top: 8px; max-width: 45%; text-align: left"> <span class="email-list-item"><a href="http://wiki.javaforum.hu/pages/viewpage.action?pageId=30998704" style="color: #326ca6; text-decoration: none">View Online</a> </span> </td>
                                                    <td class="right" width="50%" valign="top" style="font-size: 13px; padding-top: 8px; text-align: right"> <span class="email-list-item"><a href="http://wiki.javaforum.hu/users/editmyemailsettings.action" style="color: #326ca6; text-decoration: none">Manage Notifications</a> </span> <span class="email-list-divider" style="color: #505050; padding: 0 0.350em">&middot;</span> <span class="email-list-item"><a href="http://wiki.javaforum.hu/users/viewmyemailsettings.action" style="color: #326ca6; text-decoration: none">Unsubscribe from all blog posts</a> </span> </td>
                                                </tr>
                                            </tbody>
                                        </table> </td>
                                </tr>
                            </tbody>
                        </table> </td>
                </tr>
                <tr>
                    <td id="email-footer" align="center" style="font-size: 13px; padding: 0 16px 32px 16px; margin: 0"> <small style="font-size: 11px"> This message was sent by <a class="email-footer-link" style="color:#505050;font-size:11px;text-decoration:none;; color: #326ca6; text-decoration: none; color: #505050; font-size: 11px" href="http://www.atlassian.com/software/confluence">Atlassian Confluence</a> 4.2.5, the <a class="email-footer-link" style="color:#505050;font-size:11px;text-decoration:none;; color: #326ca6; text-decoration: none; color: #505050; font-size: 11px" href="http://www.atlassian.com/software/confluence/tour/enterprise-wiki.jsp">Enterprise Wiki</a> </small> </td>
                </tr>
            </tbody>
        </table>
    </body>
</html>