File: ExampleTrailHeads.java

package info (click to toggle)
java-gnome 4.1.3-10
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, sid
  • size: 9,840 kB
  • sloc: java: 27,002; ansic: 4,517; perl: 1,651; python: 1,187; makefile: 136
file content (231 lines) | stat: -rw-r--r-- 9,442 bytes parent folder | download | duplicates (5)
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
/*
 * java-gnome, a UI library for writing GTK and GNOME programs from Java!
 *
 * Copyright © 2007-2010 Operational Dynamics Consulting, Pty Ltd and Others
 *
 * The code in this file, and the program it is a part of, is made available
 * to you by its authors as open source software: you can redistribute it
 * and/or modify it under the terms of the GNU General Public License version
 * 2 ("GPL") as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
 *
 * You should have received a copy of the GPL along with this program. If not,
 * see http://www.gnu.org/licenses/. The authors of this program may be
 * contacted through http://java-gnome.sourceforge.net/.
 */
package treeview;

import org.gnome.gdk.Event;
import org.gnome.gtk.CellRendererText;
import org.gnome.gtk.DataColumn;
import org.gnome.gtk.DataColumnBoolean;
import org.gnome.gtk.DataColumnInteger;
import org.gnome.gtk.DataColumnString;
import org.gnome.gtk.Gtk;
import org.gnome.gtk.ListStore;
import org.gnome.gtk.TreeIter;
import org.gnome.gtk.TreePath;
import org.gnome.gtk.TreeView;
import org.gnome.gtk.TreeViewColumn;
import org.gnome.gtk.Widget;
import org.gnome.gtk.Window;

/**
 * A tutorial example of using a TreeView backed by a ListStore. In this
 * little demonstration, we list a number of famous hiking trails and how to
 * get to them.
 * 
 * @author Andrew Cowie
 */
public class ExampleTrailHeads
{
    public ExampleTrailHeads() {
        final Window window;
        final TreeView view;
        final ListStore model;
        TreeIter row;
        CellRendererText renderer;
        TreeViewColumn vertical;

        window = new Window();

        // ------------------------------------------------

        final DataColumnString placeName;
        final DataColumnString trailHead;
        final DataColumnString elevationFormatted;
        final DataColumnInteger elevationSort;
        final DataColumnBoolean accessibleByTrain;

        /*
         * So we begin our explorations of the TreeView API here. First thing
         * is to create a model. You'll notice we declared the variables
         * above. You don't have to do that, of course, but it makes calling
         * the ListStore constructor more palatable. More generally, you will
         * frequently have the DataColumns as instance field variables (so
         * they can be accessed throughout the file), rather than just local
         * variables. So you'll end up pre-declaring them regardless, and that
         * makes the constructor call nice and compact:
         */

        model = new ListStore(new DataColumn[] {
            placeName = new DataColumnString(),
            trailHead = new DataColumnString(),
            elevationFormatted = new DataColumnString(),
            elevationSort = new DataColumnInteger(),
            accessibleByTrain = new DataColumnBoolean()
        });

        /*
         * You almost never populate your TreeModels with data statically from
         * your source code. We have done so here to demonstrate the use of
         * appendRow() to get a new horizontal data row and then the various
         * forms of setValue() to store data in that row.
         * 
         * In practise, however, you will find the setting of data to be
         * fairly involved; after all, it takes some trouble to decide what
         * you want to display, extract if from your domain object layer and
         * format it prior to insertion into the TreeModel for display by a
         * TreeView.
         * 
         * Notice the use of Pango markup in the placeName column. This can be
         * a powerful way of improving your information density, but be aware
         * that if some rows have multiple lines and some don't, the row
         * height will be inconsistent and will look really ugly. So make sure
         * they all have the same font information and number of newlines. You
         * would use utility methods to help keep things organized, of course,
         * but we've kept it straight forward here.
         */

        row = model.appendRow();
        model.setValue(row, placeName, "Blue Mountains national park\n<small>(Six Foot Track)</small>");
        model.setValue(row, trailHead, "Katoomba, NSW, Australia");
        model.setValue(row, elevationFormatted, "1015 m");
        model.setValue(row, elevationSort, 1005);
        model.setValue(row, accessibleByTrain, true);

        row = model.appendRow();
        model.setValue(row, placeName, "Kilimanjaro\n<small>(Machame route)</small>");
        model.setValue(row, trailHead, "Nairobi, Kenya");
        model.setValue(row, elevationFormatted, "5894 m");
        model.setValue(row, elevationSort, 5894);
        model.setValue(row, accessibleByTrain, false);

        row = model.appendRow();
        model.setValue(row, placeName, "Appalachian Trail\n<small>(roller coaster section)</small>");
        model.setValue(row, trailHead, "Harpers Ferry, West Virginia, USA");
        model.setValue(row, elevationFormatted, "147 m");
        model.setValue(row, elevationSort, 147);
        model.setValue(row, accessibleByTrain, true);

        /*
         * Now onto the view side. First we need the top level TreeView which
         * is the master Widget into which everything else is mixed.
         */

        view = new TreeView(model);

        /*
         * Now the vertical display columns. The sequence is to get a
         * TreeViewColumn, then create the CellRenderer to be put into it, and
         * then set whatever data mappings are appropriate along with any
         * settings for the vertical TreeViewColumn. This is the heart of the
         * TreeView/TreeModel API
         * 
         * Note that we reuse the renderer and vertical variables; unlike the
         * DataColumns, there's no need to keep coming up with unique column
         * names as you rarely need to reference them later.
         */

        vertical = view.appendColumn();
        vertical.setTitle("Place");
        renderer = new CellRendererText(vertical);
        renderer.setMarkup(placeName);

        vertical = view.appendColumn();
        vertical.setTitle("Nearest town");
        renderer = new CellRendererText(vertical);
        renderer.setText(trailHead);
        renderer.setAlignment(0.0f, 0.0f);
        vertical.setExpand(true);

        vertical = view.appendColumn();
        vertical.setTitle("Elevation");
        renderer = new CellRendererText(vertical);
        renderer.setText(elevationFormatted);
        renderer.setAlignment(0.0f, 0.0f);

        /*
         * Because the elevation is a formatted String, it won't sort
         * properly. So we use a DataColumnInteger populated with the raw
         * altitude number to indicate the sort order. (If you don't believe
         * me, try changing the sort column to elevationFormatted instead of
         * elevationSort, and you'll see it order as 1015, 147, 5894). As
         * you'll see from the documentation, setSortColumn() also makes the
         * headers clickable, which saves you having to mess with TreeView's
         * setHeadersClickable() or TreeViewColumn's setClickable(), although
         * there are occasional use cases for them.
         * 
         * Then we call emitClicked() to force the header we want things to be
         * sorted on to actually be active. This is especially necessary if
         * you've defined sorting for more than one vertical column, but if
         * you want sorting on from the start, you need to call it.
         */

        vertical.setSortColumn(elevationSort);
        vertical.emitClicked();

        /*
         * And that's it! You've now done everything you need to have a
         * working TreeView.
         * 
         * ... except that if it's for more than information, you probably
         * want something to happen when someone clicks on a row. So, we hook
         * up a handler to the TreeView.RowActivated signal. The TreePath it
         * gives you is the useful bit.
         */

        view.connect(new TreeView.RowActivated() {
            public void onRowActivated(TreeView source, TreePath path, TreeViewColumn vertical) {
                final TreeIter row;
                final String place, height;

                row = model.getIter(path);

                place = model.getValue(row, trailHead);
                height = model.getValue(row, elevationFormatted);

                System.out.println("You want to go to " + place + " in order to climb to " + height);
            }
        });

        /*
         * The rest of this file is the usual minimum wrapper to make this
         * presentable as a Window on the display.
         */

        // ------------------------------------------------
        window.add(view);

        window.setTitle("Trail Heads");
        window.showAll();

        window.connect(new Window.DeleteEvent() {
            public boolean onDeleteEvent(Widget source, Event event) {
                Gtk.mainQuit();
                return false;
            }
        });
    }

    public static void main(String[] args) {
        Gtk.init(args);

        new ExampleTrailHeads();

        Gtk.main();
    }
}