Added support library for TreeViewList. Previously this code was subsumed in the android app.
8
android-libraries/TreeViewList/.classpath
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="src" path="src"/>
|
||||||
|
<classpathentry kind="src" path="gen"/>
|
||||||
|
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||||
|
<classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||||
|
<classpathentry kind="output" path="bin/classes"/>
|
||||||
|
</classpath>
|
33
android-libraries/TreeViewList/.project
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>TreeViewList</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
11
android-libraries/TreeViewList/AndroidManifest.xml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="pl.polidea.treeview"
|
||||||
|
android:versionCode="1"
|
||||||
|
android:versionName="1.0" >
|
||||||
|
|
||||||
|
<uses-sdk android:minSdkVersion="7" />
|
||||||
|
|
||||||
|
<application/>
|
||||||
|
|
||||||
|
</manifest>
|
@ -0,0 +1,24 @@
|
|||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
This is a small utility that provides quite configurable tree view list.
|
||||||
|
It is based on standard android list view. It separates out different
|
||||||
|
aspects of the tree: there is a separate list view, tree adapter, tree
|
||||||
|
state manager and tree state builder.
|
||||||
|
<p>
|
||||||
|
<ul>
|
||||||
|
<li>Tree view provides the frame to display the view.</li>
|
||||||
|
<li>Adapter allows to create visual representation of each tree
|
||||||
|
node.</li>
|
||||||
|
<li>State manager provides storage for tree state (connections
|
||||||
|
between parents and children, collapsed/expanded state). It provides
|
||||||
|
all the low-level tree manipulation methods.</li>
|
||||||
|
<li>Tree builder allows to build tree easily providing higher
|
||||||
|
level methods. The tree can be build either from prepared sequentially
|
||||||
|
prepared list of nodes (node id, level) or using (parent/child
|
||||||
|
relationships).</li>
|
||||||
|
<p>For now only in-memory state manager is provided, but Tree State
|
||||||
|
Manger interface is done in the way that database tree manager even for
|
||||||
|
large trees is potentially supported.
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>
|
3
android-libraries/TreeViewList/bin/jarlist.cache
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# cache for current jar dependecy. DO NOT EDIT.
|
||||||
|
# format is <lastModified> <length> <SHA-1> <path>
|
||||||
|
# Encoding is UTF-8
|
After Width: | Height: | Size: 319 B |
After Width: | Height: | Size: 231 B |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 198 B |
After Width: | Height: | Size: 167 B |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 193 B |
After Width: | Height: | Size: 155 B |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 936 B |
After Width: | Height: | Size: 315 B |
After Width: | Height: | Size: 867 B |
BIN
android-libraries/TreeViewList/bin/treeviewlist.jar
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/** Automatically generated file. DO NOT MODIFY */
|
||||||
|
package pl.polidea.treeview;
|
||||||
|
|
||||||
|
public final class BuildConfig {
|
||||||
|
public final static boolean DEBUG = true;
|
||||||
|
}
|
276
android-libraries/TreeViewList/gen/pl/polidea/treeview/R.java
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
/* AUTO-GENERATED FILE. DO NOT MODIFY.
|
||||||
|
*
|
||||||
|
* This class was automatically generated by the
|
||||||
|
* aapt tool from the resource data it found. It
|
||||||
|
* should not be modified by hand.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.polidea.treeview;
|
||||||
|
|
||||||
|
public final class R {
|
||||||
|
public static final class attr {
|
||||||
|
/** <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".
|
||||||
|
<p>This may also be a reference to a resource (in the form
|
||||||
|
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
|
||||||
|
theme attribute (in the form
|
||||||
|
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
|
||||||
|
containing a value of this type.
|
||||||
|
*/
|
||||||
|
public static int collapsible=0x7f010000;
|
||||||
|
/** <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".
|
||||||
|
<p>This may also be a reference to a resource (in the form
|
||||||
|
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
|
||||||
|
theme attribute (in the form
|
||||||
|
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
|
||||||
|
containing a value of this type.
|
||||||
|
*/
|
||||||
|
public static int handle_trackball_press=0x7f010004;
|
||||||
|
/** <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".
|
||||||
|
Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),
|
||||||
|
in (inches), mm (millimeters).
|
||||||
|
<p>This may also be a reference to a resource (in the form
|
||||||
|
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
|
||||||
|
theme attribute (in the form
|
||||||
|
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
|
||||||
|
containing a value of this type.
|
||||||
|
*/
|
||||||
|
public static int indent_width=0x7f010003;
|
||||||
|
/** <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
|
||||||
|
or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
|
||||||
|
<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
|
||||||
|
"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".
|
||||||
|
*/
|
||||||
|
public static int indicator_background=0x7f010006;
|
||||||
|
/** <p>Must be one or more (separated by '|') of the following constant values.</p>
|
||||||
|
<table>
|
||||||
|
<colgroup align="left" />
|
||||||
|
<colgroup align="left" />
|
||||||
|
<colgroup align="left" />
|
||||||
|
<tr><th>Constant</th><th>Value</th><th>Description</th></tr>
|
||||||
|
<tr><td><code>top</code></td><td>0x30</td><td> Push object to the top of its container, not changing its size. </td></tr>
|
||||||
|
<tr><td><code>bottom</code></td><td>0x50</td><td> Push object to the bottom of its container, not changing its size. </td></tr>
|
||||||
|
<tr><td><code>left</code></td><td>0x03</td><td> Push object to the left of its container, not changing its size. </td></tr>
|
||||||
|
<tr><td><code>right</code></td><td>0x05</td><td> Push object to the right of its container, not changing its size. </td></tr>
|
||||||
|
<tr><td><code>center_vertical</code></td><td>0x10</td><td> Place object in the vertical center of its container, not changing its size. </td></tr>
|
||||||
|
<tr><td><code>fill_vertical</code></td><td>0x70</td><td> Grow the vertical size of the object if needed so it completely fills its container. </td></tr>
|
||||||
|
<tr><td><code>center_horizontal</code></td><td>0x01</td><td> Place object in the horizontal center of its container, not changing its size. </td></tr>
|
||||||
|
<tr><td><code>fill_horizontal</code></td><td>0x07</td><td> Grow the horizontal size of the object if needed so it completely fills its container. </td></tr>
|
||||||
|
<tr><td><code>center</code></td><td>0x11</td><td> Place the object in the center of its container in both the vertical and horizontal axis, not changing its size. </td></tr>
|
||||||
|
<tr><td><code>fill</code></td><td>0x77</td><td> Grow the horizontal and vertical size of the object if needed so it completely fills its container. </td></tr>
|
||||||
|
<tr><td><code>clip_vertical</code></td><td>0x80</td><td> Additional option that can be set to have the top and/or bottom edges of the child clipped to its container's bounds.
|
||||||
|
The clip will be based on the vertical gravity: a top gravity will clip the bottom edge, a bottom gravity will clip the top
|
||||||
|
edge, and neither will clip both edges. </td></tr>
|
||||||
|
<tr><td><code>clip_horizontal</code></td><td>0x08</td><td> Additional option that can be set to have the left and/or right edges of the child clipped to its container's bounds.
|
||||||
|
The clip will be based on the horizontal gravity: a left gravity will clip the right edge, a right gravity will clip the
|
||||||
|
left edge, and neither will clip both edges. </td></tr>
|
||||||
|
</table>
|
||||||
|
*/
|
||||||
|
public static int indicator_gravity=0x7f010005;
|
||||||
|
/** <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
|
||||||
|
or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
|
||||||
|
<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
|
||||||
|
"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".
|
||||||
|
*/
|
||||||
|
public static int row_background=0x7f010007;
|
||||||
|
/** <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
|
||||||
|
or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
|
||||||
|
<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
|
||||||
|
"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".
|
||||||
|
*/
|
||||||
|
public static int src_collapsed=0x7f010002;
|
||||||
|
/** <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
|
||||||
|
or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
|
||||||
|
<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
|
||||||
|
"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".
|
||||||
|
*/
|
||||||
|
public static int src_expanded=0x7f010001;
|
||||||
|
}
|
||||||
|
public static final class drawable {
|
||||||
|
public static int collapsed=0x7f020000;
|
||||||
|
public static int divider=0x7f020001;
|
||||||
|
public static int expanded=0x7f020002;
|
||||||
|
public static int ic_launcher=0x7f020003;
|
||||||
|
public static int list_selector_background=0x7f020004;
|
||||||
|
public static int list_selector_background_disabled=0x7f020005;
|
||||||
|
public static int list_selector_background_focus=0x7f020006;
|
||||||
|
public static int list_selector_background_longpress=0x7f020007;
|
||||||
|
public static int list_selector_background_pressed=0x7f020008;
|
||||||
|
public static int list_selector_background_transition=0x7f020009;
|
||||||
|
}
|
||||||
|
public static final class id {
|
||||||
|
public static int bottom=0x7f040001;
|
||||||
|
public static int center=0x7f040008;
|
||||||
|
public static int center_horizontal=0x7f040006;
|
||||||
|
public static int center_vertical=0x7f040004;
|
||||||
|
public static int clip_horizontal=0x7f04000b;
|
||||||
|
public static int clip_vertical=0x7f04000a;
|
||||||
|
public static int fill=0x7f040009;
|
||||||
|
public static int fill_horizontal=0x7f040007;
|
||||||
|
public static int fill_vertical=0x7f040005;
|
||||||
|
public static int left=0x7f040002;
|
||||||
|
public static int right=0x7f040003;
|
||||||
|
public static int top=0x7f040000;
|
||||||
|
public static int treeview_list_item_frame=0x7f04000e;
|
||||||
|
public static int treeview_list_item_image=0x7f04000d;
|
||||||
|
public static int treeview_list_item_image_layout=0x7f04000c;
|
||||||
|
}
|
||||||
|
public static final class layout {
|
||||||
|
public static int tree_list_item_wrapper=0x7f030000;
|
||||||
|
}
|
||||||
|
public static final class style {
|
||||||
|
public static int treeViewListStyle=0x7f050000;
|
||||||
|
}
|
||||||
|
public static final class styleable {
|
||||||
|
/** Attributes that can be used with a TreeViewList.
|
||||||
|
<p>Includes the following attributes:</p>
|
||||||
|
<table>
|
||||||
|
<colgroup align="left" />
|
||||||
|
<colgroup align="left" />
|
||||||
|
<tr><th>Attribute</th><th>Description</th></tr>
|
||||||
|
<tr><td><code>{@link #TreeViewList_collapsible pl.polidea.treeview:collapsible}</code></td><td></td></tr>
|
||||||
|
<tr><td><code>{@link #TreeViewList_handle_trackball_press pl.polidea.treeview:handle_trackball_press}</code></td><td></td></tr>
|
||||||
|
<tr><td><code>{@link #TreeViewList_indent_width pl.polidea.treeview:indent_width}</code></td><td></td></tr>
|
||||||
|
<tr><td><code>{@link #TreeViewList_indicator_background pl.polidea.treeview:indicator_background}</code></td><td></td></tr>
|
||||||
|
<tr><td><code>{@link #TreeViewList_indicator_gravity pl.polidea.treeview:indicator_gravity}</code></td><td></td></tr>
|
||||||
|
<tr><td><code>{@link #TreeViewList_row_background pl.polidea.treeview:row_background}</code></td><td></td></tr>
|
||||||
|
<tr><td><code>{@link #TreeViewList_src_collapsed pl.polidea.treeview:src_collapsed}</code></td><td></td></tr>
|
||||||
|
<tr><td><code>{@link #TreeViewList_src_expanded pl.polidea.treeview:src_expanded}</code></td><td></td></tr>
|
||||||
|
</table>
|
||||||
|
@see #TreeViewList_collapsible
|
||||||
|
@see #TreeViewList_handle_trackball_press
|
||||||
|
@see #TreeViewList_indent_width
|
||||||
|
@see #TreeViewList_indicator_background
|
||||||
|
@see #TreeViewList_indicator_gravity
|
||||||
|
@see #TreeViewList_row_background
|
||||||
|
@see #TreeViewList_src_collapsed
|
||||||
|
@see #TreeViewList_src_expanded
|
||||||
|
*/
|
||||||
|
public static final int[] TreeViewList = {
|
||||||
|
0x7f010000, 0x7f010001, 0x7f010002, 0x7f010003,
|
||||||
|
0x7f010004, 0x7f010005, 0x7f010006, 0x7f010007
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
<p>This symbol is the offset where the {@link pl.polidea.treeview.R.attr#collapsible}
|
||||||
|
attribute's value can be found in the {@link #TreeViewList} array.
|
||||||
|
|
||||||
|
|
||||||
|
<p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".
|
||||||
|
<p>This may also be a reference to a resource (in the form
|
||||||
|
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
|
||||||
|
theme attribute (in the form
|
||||||
|
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
|
||||||
|
containing a value of this type.
|
||||||
|
@attr name android:collapsible
|
||||||
|
*/
|
||||||
|
public static final int TreeViewList_collapsible = 0;
|
||||||
|
/**
|
||||||
|
<p>This symbol is the offset where the {@link pl.polidea.treeview.R.attr#handle_trackball_press}
|
||||||
|
attribute's value can be found in the {@link #TreeViewList} array.
|
||||||
|
|
||||||
|
|
||||||
|
<p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".
|
||||||
|
<p>This may also be a reference to a resource (in the form
|
||||||
|
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
|
||||||
|
theme attribute (in the form
|
||||||
|
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
|
||||||
|
containing a value of this type.
|
||||||
|
@attr name android:handle_trackball_press
|
||||||
|
*/
|
||||||
|
public static final int TreeViewList_handle_trackball_press = 4;
|
||||||
|
/**
|
||||||
|
<p>This symbol is the offset where the {@link pl.polidea.treeview.R.attr#indent_width}
|
||||||
|
attribute's value can be found in the {@link #TreeViewList} array.
|
||||||
|
|
||||||
|
|
||||||
|
<p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".
|
||||||
|
Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),
|
||||||
|
in (inches), mm (millimeters).
|
||||||
|
<p>This may also be a reference to a resource (in the form
|
||||||
|
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
|
||||||
|
theme attribute (in the form
|
||||||
|
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
|
||||||
|
containing a value of this type.
|
||||||
|
@attr name android:indent_width
|
||||||
|
*/
|
||||||
|
public static final int TreeViewList_indent_width = 3;
|
||||||
|
/**
|
||||||
|
<p>This symbol is the offset where the {@link pl.polidea.treeview.R.attr#indicator_background}
|
||||||
|
attribute's value can be found in the {@link #TreeViewList} array.
|
||||||
|
|
||||||
|
|
||||||
|
<p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
|
||||||
|
or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
|
||||||
|
<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
|
||||||
|
"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".
|
||||||
|
@attr name android:indicator_background
|
||||||
|
*/
|
||||||
|
public static final int TreeViewList_indicator_background = 6;
|
||||||
|
/**
|
||||||
|
<p>This symbol is the offset where the {@link pl.polidea.treeview.R.attr#indicator_gravity}
|
||||||
|
attribute's value can be found in the {@link #TreeViewList} array.
|
||||||
|
|
||||||
|
|
||||||
|
<p>Must be one or more (separated by '|') of the following constant values.</p>
|
||||||
|
<table>
|
||||||
|
<colgroup align="left" />
|
||||||
|
<colgroup align="left" />
|
||||||
|
<colgroup align="left" />
|
||||||
|
<tr><th>Constant</th><th>Value</th><th>Description</th></tr>
|
||||||
|
<tr><td><code>top</code></td><td>0x30</td><td> Push object to the top of its container, not changing its size. </td></tr>
|
||||||
|
<tr><td><code>bottom</code></td><td>0x50</td><td> Push object to the bottom of its container, not changing its size. </td></tr>
|
||||||
|
<tr><td><code>left</code></td><td>0x03</td><td> Push object to the left of its container, not changing its size. </td></tr>
|
||||||
|
<tr><td><code>right</code></td><td>0x05</td><td> Push object to the right of its container, not changing its size. </td></tr>
|
||||||
|
<tr><td><code>center_vertical</code></td><td>0x10</td><td> Place object in the vertical center of its container, not changing its size. </td></tr>
|
||||||
|
<tr><td><code>fill_vertical</code></td><td>0x70</td><td> Grow the vertical size of the object if needed so it completely fills its container. </td></tr>
|
||||||
|
<tr><td><code>center_horizontal</code></td><td>0x01</td><td> Place object in the horizontal center of its container, not changing its size. </td></tr>
|
||||||
|
<tr><td><code>fill_horizontal</code></td><td>0x07</td><td> Grow the horizontal size of the object if needed so it completely fills its container. </td></tr>
|
||||||
|
<tr><td><code>center</code></td><td>0x11</td><td> Place the object in the center of its container in both the vertical and horizontal axis, not changing its size. </td></tr>
|
||||||
|
<tr><td><code>fill</code></td><td>0x77</td><td> Grow the horizontal and vertical size of the object if needed so it completely fills its container. </td></tr>
|
||||||
|
<tr><td><code>clip_vertical</code></td><td>0x80</td><td> Additional option that can be set to have the top and/or bottom edges of the child clipped to its container's bounds.
|
||||||
|
The clip will be based on the vertical gravity: a top gravity will clip the bottom edge, a bottom gravity will clip the top
|
||||||
|
edge, and neither will clip both edges. </td></tr>
|
||||||
|
<tr><td><code>clip_horizontal</code></td><td>0x08</td><td> Additional option that can be set to have the left and/or right edges of the child clipped to its container's bounds.
|
||||||
|
The clip will be based on the horizontal gravity: a left gravity will clip the right edge, a right gravity will clip the
|
||||||
|
left edge, and neither will clip both edges. </td></tr>
|
||||||
|
</table>
|
||||||
|
@attr name android:indicator_gravity
|
||||||
|
*/
|
||||||
|
public static final int TreeViewList_indicator_gravity = 5;
|
||||||
|
/**
|
||||||
|
<p>This symbol is the offset where the {@link pl.polidea.treeview.R.attr#row_background}
|
||||||
|
attribute's value can be found in the {@link #TreeViewList} array.
|
||||||
|
|
||||||
|
|
||||||
|
<p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
|
||||||
|
or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
|
||||||
|
<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
|
||||||
|
"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".
|
||||||
|
@attr name android:row_background
|
||||||
|
*/
|
||||||
|
public static final int TreeViewList_row_background = 7;
|
||||||
|
/**
|
||||||
|
<p>This symbol is the offset where the {@link pl.polidea.treeview.R.attr#src_collapsed}
|
||||||
|
attribute's value can be found in the {@link #TreeViewList} array.
|
||||||
|
|
||||||
|
|
||||||
|
<p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
|
||||||
|
or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
|
||||||
|
<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
|
||||||
|
"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".
|
||||||
|
@attr name android:src_collapsed
|
||||||
|
*/
|
||||||
|
public static final int TreeViewList_src_collapsed = 2;
|
||||||
|
/**
|
||||||
|
<p>This symbol is the offset where the {@link pl.polidea.treeview.R.attr#src_expanded}
|
||||||
|
attribute's value can be found in the {@link #TreeViewList} array.
|
||||||
|
|
||||||
|
|
||||||
|
<p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
|
||||||
|
or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
|
||||||
|
<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
|
||||||
|
"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".
|
||||||
|
@attr name android:src_expanded
|
||||||
|
*/
|
||||||
|
public static final int TreeViewList_src_expanded = 1;
|
||||||
|
};
|
||||||
|
}
|
40
android-libraries/TreeViewList/proguard.cfg
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
-optimizationpasses 5
|
||||||
|
-dontusemixedcaseclassnames
|
||||||
|
-dontskipnonpubliclibraryclasses
|
||||||
|
-dontpreverify
|
||||||
|
-verbose
|
||||||
|
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
|
||||||
|
|
||||||
|
-keep public class * extends android.app.Activity
|
||||||
|
-keep public class * extends android.app.Application
|
||||||
|
-keep public class * extends android.app.Service
|
||||||
|
-keep public class * extends android.content.BroadcastReceiver
|
||||||
|
-keep public class * extends android.content.ContentProvider
|
||||||
|
-keep public class * extends android.app.backup.BackupAgentHelper
|
||||||
|
-keep public class * extends android.preference.Preference
|
||||||
|
-keep public class com.android.vending.licensing.ILicensingService
|
||||||
|
|
||||||
|
-keepclasseswithmembernames class * {
|
||||||
|
native <methods>;
|
||||||
|
}
|
||||||
|
|
||||||
|
-keepclasseswithmembers class * {
|
||||||
|
public <init>(android.content.Context, android.util.AttributeSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
-keepclasseswithmembers class * {
|
||||||
|
public <init>(android.content.Context, android.util.AttributeSet, int);
|
||||||
|
}
|
||||||
|
|
||||||
|
-keepclassmembers class * extends android.app.Activity {
|
||||||
|
public void *(android.view.View);
|
||||||
|
}
|
||||||
|
|
||||||
|
-keepclassmembers enum * {
|
||||||
|
public static **[] values();
|
||||||
|
public static ** valueOf(java.lang.String);
|
||||||
|
}
|
||||||
|
|
||||||
|
-keep class * implements android.os.Parcelable {
|
||||||
|
public static final android.os.Parcelable$Creator *;
|
||||||
|
}
|
12
android-libraries/TreeViewList/project.properties
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# This file is automatically generated by Android Tools.
|
||||||
|
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||||
|
#
|
||||||
|
# This file must be checked in Version Control Systems.
|
||||||
|
#
|
||||||
|
# To customize properties used by the Ant build system use,
|
||||||
|
# "ant.properties", and override values to adapt the script to your
|
||||||
|
# project structure.
|
||||||
|
|
||||||
|
# Project target.
|
||||||
|
target=android-7
|
||||||
|
android.library=true
|
BIN
android-libraries/TreeViewList/res/drawable-hdpi/collapsed.png
Normal file
After Width: | Height: | Size: 455 B |
BIN
android-libraries/TreeViewList/res/drawable-hdpi/expanded.png
Normal file
After Width: | Height: | Size: 361 B |
BIN
android-libraries/TreeViewList/res/drawable-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
android-libraries/TreeViewList/res/drawable-ldpi/collapsed.png
Normal file
After Width: | Height: | Size: 313 B |
BIN
android-libraries/TreeViewList/res/drawable-ldpi/expanded.png
Normal file
After Width: | Height: | Size: 291 B |
BIN
android-libraries/TreeViewList/res/drawable-ldpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
android-libraries/TreeViewList/res/drawable-mdpi/collapsed.png
Normal file
After Width: | Height: | Size: 272 B |
BIN
android-libraries/TreeViewList/res/drawable-mdpi/expanded.png
Normal file
After Width: | Height: | Size: 254 B |
BIN
android-libraries/TreeViewList/res/drawable-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
6
android-libraries/TreeViewList/res/drawable/divider.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:src="@android:drawable/divider_horizontal_dark"
|
||||||
|
android:layout_width="fill_parent" android:layout_height="wrap_content"
|
||||||
|
android:scaleType="fitXY" android:paddingLeft="5sp"
|
||||||
|
android:paddingRight="5sp" android:paddingBottom="2sp" />
|
@ -0,0 +1,45 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2008 The Android Open Source Project Licensed under the
|
||||||
|
Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||||
|
in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
|
||||||
|
OR CONDITIONS OF ANY KIND, either express or implied. See the License for
|
||||||
|
the specific language governing permissions and limitations under the License. -->
|
||||||
|
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item android:state_window_focused="false" android:drawable="@android:color/transparent" />
|
||||||
|
|
||||||
|
<!-- Even though these two point to the same resource, have two states so
|
||||||
|
the drawable will invalidate itself when coming out of pressed state. -->
|
||||||
|
<item android:state_focused="true" android:state_enabled="false"
|
||||||
|
android:state_pressed="true" android:drawable="@drawable/list_selector_background_disabled" />
|
||||||
|
<item android:state_focused="true" android:state_enabled="false"
|
||||||
|
android:drawable="@drawable/list_selector_background_disabled" />
|
||||||
|
|
||||||
|
<item android:state_focused="true" android:state_pressed="true"
|
||||||
|
android:drawable="@drawable/list_selector_background_transition" />
|
||||||
|
<item android:state_focused="false" android:state_pressed="true"
|
||||||
|
android:drawable="@drawable/list_selector_background_transition" />
|
||||||
|
|
||||||
|
<item android:state_focused="true"
|
||||||
|
android:drawable="@drawable/list_selector_background_focus" />
|
||||||
|
|
||||||
|
<!-- !!hack!! to fill StateListDrawable.mStateListState with exactly 10
|
||||||
|
items otherwise it will throw NPE on Android 1.6 -->
|
||||||
|
|
||||||
|
<item android:animationCache="true"
|
||||||
|
android:drawable="@android:color/transparent" />
|
||||||
|
|
||||||
|
<item android:animationCache="false"
|
||||||
|
android:drawable="@android:color/transparent" />
|
||||||
|
|
||||||
|
<item android:alwaysDrawnWithCache="false"
|
||||||
|
android:drawable="@android:color/transparent" />
|
||||||
|
|
||||||
|
<item android:alwaysDrawnWithCache="true"
|
||||||
|
android:drawable="@android:color/transparent" />
|
||||||
|
|
||||||
|
|
||||||
|
</selector>
|
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 11 KiB |
@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2008 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<transition xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:drawable="@drawable/list_selector_background_pressed" />
|
||||||
|
<item android:drawable="@drawable/list_selector_background_longpress" />
|
||||||
|
</transition>
|
@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent" >
|
||||||
|
<LinearLayout android:id="@+id/treeview_list_item_image_layout" android:layout_width="80dip"
|
||||||
|
android:layout_height="fill_parent" android:gravity="right|center_vertical">
|
||||||
|
<ImageView android:id="@+id/treeview_list_item_image" android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" android:src="@drawable/collapsed" >
|
||||||
|
</ImageView>
|
||||||
|
</LinearLayout>
|
||||||
|
<FrameLayout android:id="@+id/treeview_list_item_frame" android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent" android:layout_weight="1">
|
||||||
|
</FrameLayout>
|
||||||
|
</LinearLayout>
|
42
android-libraries/TreeViewList/res/values/attrs.xml
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<declare-styleable name="TreeViewList">
|
||||||
|
<attr name="collapsible" format="boolean" />
|
||||||
|
<attr name="src_expanded" format="reference|color" />
|
||||||
|
<attr name="src_collapsed" format="reference|color" />
|
||||||
|
<attr name="indent_width" format="dimension" />
|
||||||
|
<attr name="handle_trackball_press" format="boolean" />
|
||||||
|
<attr name="indicator_gravity">
|
||||||
|
<!-- Push object to the top of its container, not changing its size. -->
|
||||||
|
<flag name="top" value="0x30" />
|
||||||
|
<!-- Push object to the bottom of its container, not changing its size. -->
|
||||||
|
<flag name="bottom" value="0x50" />
|
||||||
|
<!-- Push object to the left of its container, not changing its size. -->
|
||||||
|
<flag name="left" value="0x03" />
|
||||||
|
<!-- Push object to the right of its container, not changing its size. -->
|
||||||
|
<flag name="right" value="0x05" />
|
||||||
|
<!-- Place object in the vertical center of its container, not changing its size. -->
|
||||||
|
<flag name="center_vertical" value="0x10" />
|
||||||
|
<!-- Grow the vertical size of the object if needed so it completely fills its container. -->
|
||||||
|
<flag name="fill_vertical" value="0x70" />
|
||||||
|
<!-- Place object in the horizontal center of its container, not changing its size. -->
|
||||||
|
<flag name="center_horizontal" value="0x01" />
|
||||||
|
<!-- Grow the horizontal size of the object if needed so it completely fills its container. -->
|
||||||
|
<flag name="fill_horizontal" value="0x07" />
|
||||||
|
<!-- Place the object in the center of its container in both the vertical and horizontal axis, not changing its size. -->
|
||||||
|
<flag name="center" value="0x11" />
|
||||||
|
<!-- Grow the horizontal and vertical size of the object if needed so it completely fills its container. -->
|
||||||
|
<flag name="fill" value="0x77" />
|
||||||
|
<!-- Additional option that can be set to have the top and/or bottom edges of the child clipped to its container's bounds.
|
||||||
|
The clip will be based on the vertical gravity: a top gravity will clip the bottom edge, a bottom gravity will clip the top
|
||||||
|
edge, and neither will clip both edges. -->
|
||||||
|
<flag name="clip_vertical" value="0x80" />
|
||||||
|
<!-- Additional option that can be set to have the left and/or right edges of the child clipped to its container's bounds.
|
||||||
|
The clip will be based on the horizontal gravity: a left gravity will clip the right edge, a right gravity will clip the
|
||||||
|
left edge, and neither will clip both edges. -->
|
||||||
|
<flag name="clip_horizontal" value="0x08" />
|
||||||
|
</attr>
|
||||||
|
<attr name="indicator_background" format="reference|color" />
|
||||||
|
<attr name="row_background" format="reference|color" />
|
||||||
|
</declare-styleable>
|
||||||
|
</resources>
|
7
android-libraries/TreeViewList/res/values/styles.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<style parent="@android:attr/listViewStyle" name="treeViewListStyle">
|
||||||
|
<item name="android:background">@android:color/white</item>
|
||||||
|
<item name="android:divider">@drawable/divider</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
@ -0,0 +1,315 @@
|
|||||||
|
package pl.polidea.treeview;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.DataSetObserver;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.BaseAdapter;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.FrameLayout.LayoutParams;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.ImageView.ScaleType;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.ListAdapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapter used to feed the table view.
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* class for ID of the tree
|
||||||
|
*/
|
||||||
|
public abstract class AbstractTreeViewAdapter<T> extends BaseAdapter implements
|
||||||
|
ListAdapter {
|
||||||
|
private final TreeStateManager<T> treeStateManager;
|
||||||
|
private final int numberOfLevels;
|
||||||
|
private final LayoutInflater layoutInflater;
|
||||||
|
|
||||||
|
private int indentWidth = 0;
|
||||||
|
private int indicatorGravity = 0;
|
||||||
|
private Drawable collapsedDrawable;
|
||||||
|
private Drawable expandedDrawable;
|
||||||
|
private Drawable indicatorBackgroundDrawable;
|
||||||
|
private Drawable rowBackgroundDrawable;
|
||||||
|
|
||||||
|
private final OnClickListener indicatorClickListener = new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(final View v) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
final T id = (T) v.getTag();
|
||||||
|
expandCollapse(id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private boolean collapsible;
|
||||||
|
private final Activity activity;
|
||||||
|
|
||||||
|
public Activity getActivity() {
|
||||||
|
return activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TreeStateManager<T> getManager() {
|
||||||
|
return treeStateManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void expandCollapse(final T id) {
|
||||||
|
final TreeNodeInfo<T> info = treeStateManager.getNodeInfo(id);
|
||||||
|
if (!info.isWithChildren()) {
|
||||||
|
// ignore - no default action
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (info.isExpanded()) {
|
||||||
|
treeStateManager.collapseChildren(id);
|
||||||
|
} else {
|
||||||
|
treeStateManager.expandDirectChildren(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calculateIndentWidth() {
|
||||||
|
if (expandedDrawable != null) {
|
||||||
|
indentWidth = Math.max(getIndentWidth(),
|
||||||
|
expandedDrawable.getIntrinsicWidth());
|
||||||
|
}
|
||||||
|
if (collapsedDrawable != null) {
|
||||||
|
indentWidth = Math.max(getIndentWidth(),
|
||||||
|
collapsedDrawable.getIntrinsicWidth());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractTreeViewAdapter(final Activity activity,
|
||||||
|
final TreeStateManager<T> treeStateManager, final int numberOfLevels) {
|
||||||
|
this.activity = activity;
|
||||||
|
this.treeStateManager = treeStateManager;
|
||||||
|
this.layoutInflater = (LayoutInflater) activity
|
||||||
|
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
this.numberOfLevels = numberOfLevels;
|
||||||
|
this.collapsedDrawable = null;
|
||||||
|
this.expandedDrawable = null;
|
||||||
|
this.rowBackgroundDrawable = null;
|
||||||
|
this.indicatorBackgroundDrawable = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerDataSetObserver(final DataSetObserver observer) {
|
||||||
|
treeStateManager.registerDataSetObserver(observer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unregisterDataSetObserver(final DataSetObserver observer) {
|
||||||
|
treeStateManager.unregisterDataSetObserver(observer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCount() {
|
||||||
|
return treeStateManager.getVisibleCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getItem(final int position) {
|
||||||
|
return getItemId(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getTreeId(final int position) {
|
||||||
|
return treeStateManager.getVisibleList().get(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TreeNodeInfo<T> getTreeNodeInfo(final int position) {
|
||||||
|
return treeStateManager.getNodeInfo(getTreeId(position));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasStableIds() { // NOPMD
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(final int position) {
|
||||||
|
return getTreeNodeInfo(position).getLevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getViewTypeCount() {
|
||||||
|
return numberOfLevels;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return getCount() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areAllItemsEnabled() { // NOPMD
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled(final int position) { // NOPMD
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getTreeListItemWrapperId() {
|
||||||
|
return R.layout.tree_list_item_wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final View getView(final int position, final View convertView,
|
||||||
|
final ViewGroup parent) {
|
||||||
|
final TreeNodeInfo<T> nodeInfo = getTreeNodeInfo(position);
|
||||||
|
if (convertView == null) {
|
||||||
|
final LinearLayout layout = (LinearLayout) layoutInflater.inflate(
|
||||||
|
getTreeListItemWrapperId(), null);
|
||||||
|
return populateTreeItem(layout, getNewChildView(nodeInfo),
|
||||||
|
nodeInfo, true);
|
||||||
|
} else {
|
||||||
|
final LinearLayout linear = (LinearLayout) convertView;
|
||||||
|
final FrameLayout frameLayout = (FrameLayout) linear
|
||||||
|
.findViewById(R.id.treeview_list_item_frame);
|
||||||
|
final View childView = frameLayout.getChildAt(0);
|
||||||
|
updateView(childView, nodeInfo);
|
||||||
|
return populateTreeItem(linear, childView, nodeInfo, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when new view is to be created.
|
||||||
|
*
|
||||||
|
* @param treeNodeInfo
|
||||||
|
* node info
|
||||||
|
* @return view that should be displayed as tree content
|
||||||
|
*/
|
||||||
|
public abstract View getNewChildView(TreeNodeInfo<T> treeNodeInfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when new view is going to be reused. You should update the view
|
||||||
|
* and fill it in with the data required to display the new information. You
|
||||||
|
* can also create a new view, which will mean that the old view will not be
|
||||||
|
* reused.
|
||||||
|
*
|
||||||
|
* @param view
|
||||||
|
* view that should be updated with the new values
|
||||||
|
* @param treeNodeInfo
|
||||||
|
* node info used to populate the view
|
||||||
|
* @return view to used as row indented content
|
||||||
|
*/
|
||||||
|
public abstract View updateView(View view, TreeNodeInfo<T> treeNodeInfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves background drawable for the node.
|
||||||
|
*
|
||||||
|
* @param treeNodeInfo
|
||||||
|
* node info
|
||||||
|
* @return drawable returned as background for the whole row. Might be null,
|
||||||
|
* then default background is used
|
||||||
|
*/
|
||||||
|
public Drawable getBackgroundDrawable(final TreeNodeInfo<T> treeNodeInfo) { // NOPMD
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Drawable getDrawableOrDefaultBackground(final Drawable r) {
|
||||||
|
if (r == null) {
|
||||||
|
return activity.getResources()
|
||||||
|
.getDrawable(R.drawable.list_selector_background).mutate();
|
||||||
|
} else {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final LinearLayout populateTreeItem(final LinearLayout layout,
|
||||||
|
final View childView, final TreeNodeInfo<T> nodeInfo,
|
||||||
|
final boolean newChildView) {
|
||||||
|
final Drawable individualRowDrawable = getBackgroundDrawable(nodeInfo);
|
||||||
|
layout.setBackgroundDrawable(individualRowDrawable == null ? getDrawableOrDefaultBackground(rowBackgroundDrawable)
|
||||||
|
: individualRowDrawable);
|
||||||
|
final LinearLayout.LayoutParams indicatorLayoutParams = new LinearLayout.LayoutParams(
|
||||||
|
calculateIndentation(nodeInfo), LayoutParams.FILL_PARENT);
|
||||||
|
final LinearLayout indicatorLayout = (LinearLayout) layout
|
||||||
|
.findViewById(R.id.treeview_list_item_image_layout);
|
||||||
|
indicatorLayout.setGravity(indicatorGravity);
|
||||||
|
indicatorLayout.setLayoutParams(indicatorLayoutParams);
|
||||||
|
final ImageView image = (ImageView) layout
|
||||||
|
.findViewById(R.id.treeview_list_item_image);
|
||||||
|
image.setImageDrawable(getDrawable(nodeInfo));
|
||||||
|
image.setBackgroundDrawable(getDrawableOrDefaultBackground(indicatorBackgroundDrawable));
|
||||||
|
image.setScaleType(ScaleType.CENTER);
|
||||||
|
image.setTag(nodeInfo.getId());
|
||||||
|
if (nodeInfo.isWithChildren() && collapsible) {
|
||||||
|
image.setOnClickListener(indicatorClickListener);
|
||||||
|
} else {
|
||||||
|
image.setOnClickListener(null);
|
||||||
|
}
|
||||||
|
layout.setTag(nodeInfo.getId());
|
||||||
|
final FrameLayout frameLayout = (FrameLayout) layout
|
||||||
|
.findViewById(R.id.treeview_list_item_frame);
|
||||||
|
final FrameLayout.LayoutParams childParams = new FrameLayout.LayoutParams(
|
||||||
|
LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
|
||||||
|
if (newChildView) {
|
||||||
|
frameLayout.addView(childView, childParams);
|
||||||
|
}
|
||||||
|
frameLayout.setTag(nodeInfo.getId());
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int calculateIndentation(final TreeNodeInfo<T> nodeInfo) {
|
||||||
|
return getIndentWidth() * (nodeInfo.getLevel() + (collapsible ? 1 : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Drawable getDrawable(final TreeNodeInfo<T> nodeInfo) {
|
||||||
|
if (!nodeInfo.isWithChildren() || !collapsible) {
|
||||||
|
return getDrawableOrDefaultBackground(indicatorBackgroundDrawable);
|
||||||
|
}
|
||||||
|
if (nodeInfo.isExpanded()) {
|
||||||
|
return expandedDrawable;
|
||||||
|
} else {
|
||||||
|
return collapsedDrawable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIndicatorGravity(final int indicatorGravity) {
|
||||||
|
this.indicatorGravity = indicatorGravity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCollapsedDrawable(final Drawable collapsedDrawable) {
|
||||||
|
this.collapsedDrawable = collapsedDrawable;
|
||||||
|
calculateIndentWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpandedDrawable(final Drawable expandedDrawable) {
|
||||||
|
this.expandedDrawable = expandedDrawable;
|
||||||
|
calculateIndentWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIndentWidth(final int indentWidth) {
|
||||||
|
this.indentWidth = indentWidth;
|
||||||
|
calculateIndentWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRowBackgroundDrawable(final Drawable rowBackgroundDrawable) {
|
||||||
|
this.rowBackgroundDrawable = rowBackgroundDrawable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIndicatorBackgroundDrawable(
|
||||||
|
final Drawable indicatorBackgroundDrawable) {
|
||||||
|
this.indicatorBackgroundDrawable = indicatorBackgroundDrawable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCollapsible(final boolean collapsible) {
|
||||||
|
this.collapsible = collapsible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refresh() {
|
||||||
|
treeStateManager.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getIndentWidth() {
|
||||||
|
return indentWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void handleItemClick(final View view, final Object id) {
|
||||||
|
expandCollapse((T) id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
package pl.polidea.treeview;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Node. It is package protected so that it cannot be used outside.
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* type of the identifier used by the tree
|
||||||
|
*/
|
||||||
|
class InMemoryTreeNode<T> implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private final T id;
|
||||||
|
private final T parent;
|
||||||
|
private final int level;
|
||||||
|
private boolean visible = true;
|
||||||
|
private final List<InMemoryTreeNode<T>> children = new LinkedList<InMemoryTreeNode<T>>();
|
||||||
|
private List<T> childIdListCache = null;
|
||||||
|
|
||||||
|
public InMemoryTreeNode(final T id, final T parent, final int level,
|
||||||
|
final boolean visible) {
|
||||||
|
super();
|
||||||
|
this.id = id;
|
||||||
|
this.parent = parent;
|
||||||
|
this.level = level;
|
||||||
|
this.visible = visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int indexOf(final T id) {
|
||||||
|
return getChildIdList().indexOf(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache is built lasily only if needed. The cache is cleaned on any
|
||||||
|
* structure change for that node!).
|
||||||
|
*
|
||||||
|
* @return list of ids of children
|
||||||
|
*/
|
||||||
|
public synchronized List<T> getChildIdList() {
|
||||||
|
if (childIdListCache == null) {
|
||||||
|
childIdListCache = new LinkedList<T>();
|
||||||
|
for (final InMemoryTreeNode<T> n : children) {
|
||||||
|
childIdListCache.add(n.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return childIdListCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isVisible() {
|
||||||
|
return visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVisible(final boolean visible) {
|
||||||
|
this.visible = visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getChildrenListSize() {
|
||||||
|
return children.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized InMemoryTreeNode<T> add(final int index, final T child,
|
||||||
|
final boolean visible) {
|
||||||
|
childIdListCache = null;
|
||||||
|
// Note! top levell children are always visible (!)
|
||||||
|
final InMemoryTreeNode<T> newNode = new InMemoryTreeNode<T>(child,
|
||||||
|
getId(), getLevel() + 1, getId() == null ? true : visible);
|
||||||
|
children.add(index, newNode);
|
||||||
|
return newNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note. This method should technically return unmodifiable collection, but
|
||||||
|
* for performance reason on small devices we do not do it.
|
||||||
|
*
|
||||||
|
* @return children list
|
||||||
|
*/
|
||||||
|
public List<InMemoryTreeNode<T>> getChildren() {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void clearChildren() {
|
||||||
|
children.clear();
|
||||||
|
childIdListCache = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void removeChild(final T child) {
|
||||||
|
final int childIndex = indexOf(child);
|
||||||
|
if (childIndex != -1) {
|
||||||
|
children.remove(childIndex);
|
||||||
|
childIdListCache = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "InMemoryTreeNode [id=" + getId() + ", parent=" + getParent()
|
||||||
|
+ ", level=" + getLevel() + ", visible=" + visible
|
||||||
|
+ ", children=" + children + ", childIdListCache="
|
||||||
|
+ childIdListCache + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
T getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
T getParent() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getLevel() {
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,374 @@
|
|||||||
|
package pl.polidea.treeview;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import android.database.DataSetObserver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In-memory manager of tree state.
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* type of identifier
|
||||||
|
*/
|
||||||
|
public class InMemoryTreeStateManager<T> implements TreeStateManager<T> {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private final Map<T, InMemoryTreeNode<T>> allNodes = new HashMap<T, InMemoryTreeNode<T>>();
|
||||||
|
private final InMemoryTreeNode<T> topSentinel = new InMemoryTreeNode<T>(
|
||||||
|
null, null, -1, true);
|
||||||
|
private transient List<T> visibleListCache = null; // lasy initialised
|
||||||
|
private transient List<T> unmodifiableVisibleList = null;
|
||||||
|
private boolean visibleByDefault = true;
|
||||||
|
private final transient Set<DataSetObserver> observers = new HashSet<DataSetObserver>();
|
||||||
|
|
||||||
|
private synchronized void internalDataSetChanged() {
|
||||||
|
visibleListCache = null;
|
||||||
|
unmodifiableVisibleList = null;
|
||||||
|
for (final DataSetObserver observer : observers) {
|
||||||
|
observer.onChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true new nodes are visible by default.
|
||||||
|
*
|
||||||
|
* @param visibleByDefault
|
||||||
|
* if true, then newly added nodes are expanded by default
|
||||||
|
*/
|
||||||
|
public void setVisibleByDefault(final boolean visibleByDefault) {
|
||||||
|
this.visibleByDefault = visibleByDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
private InMemoryTreeNode<T> getNodeFromTreeOrThrow(final T id) {
|
||||||
|
if (id == null) {
|
||||||
|
throw new NodeNotInTreeException("(null)");
|
||||||
|
}
|
||||||
|
final InMemoryTreeNode<T> node = allNodes.get(id);
|
||||||
|
if (node == null) {
|
||||||
|
throw new NodeNotInTreeException(id.toString());
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
private InMemoryTreeNode<T> getNodeFromTreeOrThrowAllowRoot(final T id) {
|
||||||
|
if (id == null) {
|
||||||
|
return topSentinel;
|
||||||
|
}
|
||||||
|
return getNodeFromTreeOrThrow(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectNodeNotInTreeYet(final T id) {
|
||||||
|
final InMemoryTreeNode<T> node = allNodes.get(id);
|
||||||
|
if (node != null) {
|
||||||
|
throw new NodeAlreadyInTreeException(id.toString(), node.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized TreeNodeInfo<T> getNodeInfo(final T id) {
|
||||||
|
final InMemoryTreeNode<T> node = getNodeFromTreeOrThrow(id);
|
||||||
|
final List<InMemoryTreeNode<T>> children = node.getChildren();
|
||||||
|
boolean expanded = false;
|
||||||
|
if (!children.isEmpty() && children.get(0).isVisible()) {
|
||||||
|
expanded = true;
|
||||||
|
}
|
||||||
|
return new TreeNodeInfo<T>(id, node.getLevel(), !children.isEmpty(),
|
||||||
|
node.isVisible(), expanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized List<T> getChildren(final T id) {
|
||||||
|
final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(id);
|
||||||
|
return node.getChildIdList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized T getParent(final T id) {
|
||||||
|
final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(id);
|
||||||
|
return node.getParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean getChildrenVisibility(final InMemoryTreeNode<T> node) {
|
||||||
|
boolean visibility;
|
||||||
|
final List<InMemoryTreeNode<T>> children = node.getChildren();
|
||||||
|
if (children.isEmpty()) {
|
||||||
|
visibility = visibleByDefault;
|
||||||
|
} else {
|
||||||
|
visibility = children.get(0).isVisible();
|
||||||
|
}
|
||||||
|
return visibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void addBeforeChild(final T parent, final T newChild,
|
||||||
|
final T beforeChild) {
|
||||||
|
expectNodeNotInTreeYet(newChild);
|
||||||
|
final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(parent);
|
||||||
|
final boolean visibility = getChildrenVisibility(node);
|
||||||
|
// top nodes are always expanded.
|
||||||
|
if (beforeChild == null) {
|
||||||
|
final InMemoryTreeNode<T> added = node.add(0, newChild, visibility);
|
||||||
|
allNodes.put(newChild, added);
|
||||||
|
} else {
|
||||||
|
final int index = node.indexOf(beforeChild);
|
||||||
|
final InMemoryTreeNode<T> added = node.add(index == -1 ? 0 : index,
|
||||||
|
newChild, visibility);
|
||||||
|
allNodes.put(newChild, added);
|
||||||
|
}
|
||||||
|
if (visibility) {
|
||||||
|
internalDataSetChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void addAfterChild(final T parent, final T newChild,
|
||||||
|
final T afterChild) {
|
||||||
|
expectNodeNotInTreeYet(newChild);
|
||||||
|
final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(parent);
|
||||||
|
final boolean visibility = getChildrenVisibility(node);
|
||||||
|
if (afterChild == null) {
|
||||||
|
final InMemoryTreeNode<T> added = node.add(
|
||||||
|
node.getChildrenListSize(), newChild, visibility);
|
||||||
|
allNodes.put(newChild, added);
|
||||||
|
} else {
|
||||||
|
final int index = node.indexOf(afterChild);
|
||||||
|
final InMemoryTreeNode<T> added = node.add(
|
||||||
|
index == -1 ? node.getChildrenListSize() : index, newChild,
|
||||||
|
visibility);
|
||||||
|
allNodes.put(newChild, added);
|
||||||
|
}
|
||||||
|
if (visibility) {
|
||||||
|
internalDataSetChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void removeNodeRecursively(final T id) {
|
||||||
|
final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(id);
|
||||||
|
final boolean visibleNodeChanged = removeNodeRecursively(node);
|
||||||
|
final T parent = node.getParent();
|
||||||
|
final InMemoryTreeNode<T> parentNode = getNodeFromTreeOrThrowAllowRoot(parent);
|
||||||
|
parentNode.removeChild(id);
|
||||||
|
if (visibleNodeChanged) {
|
||||||
|
internalDataSetChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean removeNodeRecursively(final InMemoryTreeNode<T> node) {
|
||||||
|
boolean visibleNodeChanged = false;
|
||||||
|
for (final InMemoryTreeNode<T> child : node.getChildren()) {
|
||||||
|
if (removeNodeRecursively(child)) {
|
||||||
|
visibleNodeChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node.clearChildren();
|
||||||
|
if (node.getId() != null) {
|
||||||
|
allNodes.remove(node.getId());
|
||||||
|
if (node.isVisible()) {
|
||||||
|
visibleNodeChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return visibleNodeChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setChildrenVisibility(final InMemoryTreeNode<T> node,
|
||||||
|
final boolean visible, final boolean recursive) {
|
||||||
|
for (final InMemoryTreeNode<T> child : node.getChildren()) {
|
||||||
|
child.setVisible(visible);
|
||||||
|
if (recursive) {
|
||||||
|
setChildrenVisibility(child, visible, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void expandDirectChildren(final T id) {
|
||||||
|
final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(id);
|
||||||
|
setChildrenVisibility(node, true, false);
|
||||||
|
internalDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void expandEverythingBelow(final T id) {
|
||||||
|
final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(id);
|
||||||
|
setChildrenVisibility(node, true, true);
|
||||||
|
internalDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void collapseChildren(final T id) {
|
||||||
|
final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(id);
|
||||||
|
if (node == topSentinel) {
|
||||||
|
for (final InMemoryTreeNode<T> n : topSentinel.getChildren()) {
|
||||||
|
setChildrenVisibility(n, false, true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setChildrenVisibility(node, false, true);
|
||||||
|
}
|
||||||
|
internalDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized T getNextSibling(final T id) {
|
||||||
|
final T parent = getParent(id);
|
||||||
|
final InMemoryTreeNode<T> parentNode = getNodeFromTreeOrThrowAllowRoot(parent);
|
||||||
|
boolean returnNext = false;
|
||||||
|
for (final InMemoryTreeNode<T> child : parentNode.getChildren()) {
|
||||||
|
if (returnNext) {
|
||||||
|
return child.getId();
|
||||||
|
}
|
||||||
|
if (child.getId().equals(id)) {
|
||||||
|
returnNext = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized T getPreviousSibling(final T id) {
|
||||||
|
final T parent = getParent(id);
|
||||||
|
final InMemoryTreeNode<T> parentNode = getNodeFromTreeOrThrowAllowRoot(parent);
|
||||||
|
final T previousSibling = null;
|
||||||
|
for (final InMemoryTreeNode<T> child : parentNode.getChildren()) {
|
||||||
|
if (child.getId().equals(id)) {
|
||||||
|
return previousSibling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized boolean isInTree(final T id) {
|
||||||
|
return allNodes.containsKey(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized int getVisibleCount() {
|
||||||
|
return getVisibleList().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized List<T> getVisibleList() {
|
||||||
|
T currentId = null;
|
||||||
|
if (visibleListCache == null) {
|
||||||
|
visibleListCache = new ArrayList<T>(allNodes.size());
|
||||||
|
do {
|
||||||
|
currentId = getNextVisible(currentId);
|
||||||
|
if (currentId == null) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
visibleListCache.add(currentId);
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
if (unmodifiableVisibleList == null) {
|
||||||
|
unmodifiableVisibleList = Collections
|
||||||
|
.unmodifiableList(visibleListCache);
|
||||||
|
}
|
||||||
|
return unmodifiableVisibleList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized T getNextVisible(final T id) {
|
||||||
|
final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(id);
|
||||||
|
if (!node.isVisible()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final List<InMemoryTreeNode<T>> children = node.getChildren();
|
||||||
|
if (!children.isEmpty()) {
|
||||||
|
final InMemoryTreeNode<T> firstChild = children.get(0);
|
||||||
|
if (firstChild.isVisible()) {
|
||||||
|
return firstChild.getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final T sibl = getNextSibling(id);
|
||||||
|
if (sibl != null) {
|
||||||
|
return sibl;
|
||||||
|
}
|
||||||
|
T parent = node.getParent();
|
||||||
|
do {
|
||||||
|
if (parent == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final T parentSibling = getNextSibling(parent);
|
||||||
|
if (parentSibling != null) {
|
||||||
|
return parentSibling;
|
||||||
|
}
|
||||||
|
parent = getNodeFromTreeOrThrow(parent).getParent();
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void registerDataSetObserver(
|
||||||
|
final DataSetObserver observer) {
|
||||||
|
observers.add(observer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void unregisterDataSetObserver(
|
||||||
|
final DataSetObserver observer) {
|
||||||
|
observers.remove(observer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLevel(final T id) {
|
||||||
|
return getNodeFromTreeOrThrow(id).getLevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer[] getHierarchyDescription(final T id) {
|
||||||
|
final int level = getLevel(id);
|
||||||
|
final Integer[] hierarchy = new Integer[level + 1];
|
||||||
|
int currentLevel = level;
|
||||||
|
T currentId = id;
|
||||||
|
T parent = getParent(currentId);
|
||||||
|
while (currentLevel >= 0) {
|
||||||
|
hierarchy[currentLevel--] = getChildren(parent).indexOf(currentId);
|
||||||
|
currentId = parent;
|
||||||
|
parent = getParent(parent);
|
||||||
|
}
|
||||||
|
return hierarchy;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendToSb(final StringBuilder sb, final T id) {
|
||||||
|
if (id != null) {
|
||||||
|
final TreeNodeInfo<T> node = getNodeInfo(id);
|
||||||
|
final int indent = node.getLevel() * 4;
|
||||||
|
final char[] indentString = new char[indent];
|
||||||
|
Arrays.fill(indentString, ' ');
|
||||||
|
sb.append(indentString);
|
||||||
|
sb.append(node.toString());
|
||||||
|
sb.append(Arrays.asList(getHierarchyDescription(id)).toString());
|
||||||
|
sb.append("\n");
|
||||||
|
}
|
||||||
|
final List<T> children = getChildren(id);
|
||||||
|
for (final T child : children) {
|
||||||
|
appendToSb(sb, child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized String toString() {
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
appendToSb(sb, null);
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void clear() {
|
||||||
|
allNodes.clear();
|
||||||
|
topSentinel.clearChildren();
|
||||||
|
internalDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refresh() {
|
||||||
|
internalDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package pl.polidea.treeview;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The node being added is already in the tree.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class NodeAlreadyInTreeException extends RuntimeException {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public NodeAlreadyInTreeException(final String id, final String oldNode) {
|
||||||
|
super("The node has already been added to the tree: " + id + ". Old node is:" + oldNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package pl.polidea.treeview;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This exception is thrown when the tree does not contain node requested.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class NodeNotInTreeException extends RuntimeException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public NodeNotInTreeException(final String id) {
|
||||||
|
super("The tree does not contain the node specified: " + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,126 @@
|
|||||||
|
package pl.polidea.treeview;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows to build tree easily in sequential mode (you have to know levels of
|
||||||
|
* all the tree elements upfront). You should rather use this class rather than
|
||||||
|
* manager if you build initial tree from some external data source.
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
*/
|
||||||
|
public class TreeBuilder<T> {
|
||||||
|
private static final String TAG = TreeBuilder.class.getSimpleName();
|
||||||
|
|
||||||
|
private final TreeStateManager<T> manager;
|
||||||
|
|
||||||
|
private T lastAddedId = null;
|
||||||
|
private int lastLevel = -1;
|
||||||
|
|
||||||
|
public TreeBuilder(final TreeStateManager<T> manager) {
|
||||||
|
this.manager = manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
manager.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds new relation to existing tree. Child is set as the last child of the
|
||||||
|
* parent node. Parent has to already exist in the tree, child cannot yet
|
||||||
|
* exist. This method is mostly useful in case you add entries layer by
|
||||||
|
* layer - i.e. first top level entries, then children for all parents, then
|
||||||
|
* grand-children and so on.
|
||||||
|
*
|
||||||
|
* @param parent
|
||||||
|
* parent id
|
||||||
|
* @param child
|
||||||
|
* child id
|
||||||
|
*/
|
||||||
|
public synchronized void addRelation(final T parent, final T child) {
|
||||||
|
Log.d(TAG, "Adding relation parent:" + parent + " -> child: " + child);
|
||||||
|
manager.addAfterChild(parent, child, null);
|
||||||
|
lastAddedId = child;
|
||||||
|
lastLevel = manager.getLevel(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds sequentially new node. Using this method is the simplest way of
|
||||||
|
* building tree - if you have all the elements in the sequence as they
|
||||||
|
* should be displayed in fully-expanded tree. You can combine it with add
|
||||||
|
* relation - for example you can add information about few levels using
|
||||||
|
* {@link addRelation} and then after the right level is added as parent,
|
||||||
|
* you can continue adding them using sequential operation.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* id of the node
|
||||||
|
* @param level
|
||||||
|
* its level
|
||||||
|
*/
|
||||||
|
public synchronized void sequentiallyAddNextNode(final T id, final int level) {
|
||||||
|
Log.d(TAG, "Adding sequentiall node " + id + " at level " + level);
|
||||||
|
if (lastAddedId == null) {
|
||||||
|
addNodeToParentOneLevelDown(null, id, level);
|
||||||
|
} else {
|
||||||
|
if (level <= lastLevel) {
|
||||||
|
final T parent = findParentAtLevel(lastAddedId, level - 1);
|
||||||
|
addNodeToParentOneLevelDown(parent, id, level);
|
||||||
|
} else {
|
||||||
|
addNodeToParentOneLevelDown(lastAddedId, id, level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find parent of the node at the level specified.
|
||||||
|
*
|
||||||
|
* @param node
|
||||||
|
* node from which we start
|
||||||
|
* @param levelToFind
|
||||||
|
* level which we are looking for
|
||||||
|
* @return the node found (null if it is topmost node).
|
||||||
|
*/
|
||||||
|
private T findParentAtLevel(final T node, final int levelToFind) {
|
||||||
|
T parent = manager.getParent(node);
|
||||||
|
while (parent != null) {
|
||||||
|
if (manager.getLevel(parent) == levelToFind) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
parent = manager.getParent(parent);
|
||||||
|
}
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds note to parent at the level specified. But it verifies that the
|
||||||
|
* level is one level down than the parent!
|
||||||
|
*
|
||||||
|
* @param parent
|
||||||
|
* parent parent
|
||||||
|
* @param id
|
||||||
|
* new node id
|
||||||
|
* @param level
|
||||||
|
* should always be parent's level + 1
|
||||||
|
*/
|
||||||
|
private void addNodeToParentOneLevelDown(final T parent, final T id,
|
||||||
|
final int level) {
|
||||||
|
if (parent == null && level != 0) {
|
||||||
|
throw new TreeConfigurationException("Trying to add new id " + id
|
||||||
|
+ " to top level with level != 0 (" + level + ")");
|
||||||
|
}
|
||||||
|
if (parent != null && manager.getLevel(parent) != level - 1) {
|
||||||
|
throw new TreeConfigurationException("Trying to add new id " + id
|
||||||
|
+ " <" + level + "> to " + parent + " <"
|
||||||
|
+ manager.getLevel(parent)
|
||||||
|
+ ">. The difference in levels up is bigger than 1.");
|
||||||
|
}
|
||||||
|
manager.addAfterChild(parent, id, null);
|
||||||
|
setLastAdded(id, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setLastAdded(final T id, final int level) {
|
||||||
|
lastAddedId = id;
|
||||||
|
lastLevel = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package pl.polidea.treeview;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown when there is a problem with configuring tree.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TreeConfigurationException extends RuntimeException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public TreeConfigurationException(final String detailMessage) {
|
||||||
|
super(detailMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
package pl.polidea.treeview;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about the node.
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* type of the id for the tree
|
||||||
|
*/
|
||||||
|
public class TreeNodeInfo<T> {
|
||||||
|
private final T id;
|
||||||
|
private final int level;
|
||||||
|
private final boolean withChildren;
|
||||||
|
private final boolean visible;
|
||||||
|
private final boolean expanded;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the node information.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* id of the node
|
||||||
|
* @param level
|
||||||
|
* level of the node
|
||||||
|
* @param withChildren
|
||||||
|
* whether the node has children.
|
||||||
|
* @param visible
|
||||||
|
* whether the tree node is visible.
|
||||||
|
* @param expanded
|
||||||
|
* whether the tree node is expanded
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public TreeNodeInfo(final T id, final int level,
|
||||||
|
final boolean withChildren, final boolean visible,
|
||||||
|
final boolean expanded) {
|
||||||
|
super();
|
||||||
|
this.id = id;
|
||||||
|
this.level = level;
|
||||||
|
this.withChildren = withChildren;
|
||||||
|
this.visible = visible;
|
||||||
|
this.expanded = expanded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isWithChildren() {
|
||||||
|
return withChildren;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isVisible() {
|
||||||
|
return visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isExpanded() {
|
||||||
|
return expanded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLevel() {
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "TreeNodeInfo [id=" + id + ", level=" + level
|
||||||
|
+ ", withChildren=" + withChildren + ", visible=" + visible
|
||||||
|
+ ", expanded=" + expanded + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,193 @@
|
|||||||
|
package pl.polidea.treeview;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import android.database.DataSetObserver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages information about state of the tree. It only keeps information about
|
||||||
|
* tree elements, not the elements themselves.
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* type of the identifier for nodes in the tree
|
||||||
|
*/
|
||||||
|
public interface TreeStateManager<T> extends Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns array of integers showing the location of the node in hierarchy.
|
||||||
|
* It corresponds to heading numbering. {0,0,0} in 3 level node is the first
|
||||||
|
* node {0,0,1} is second leaf (assuming that there are two leaves in first
|
||||||
|
* subnode of the first node).
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* id of the node
|
||||||
|
* @return textual description of the hierarchy in tree for the node.
|
||||||
|
*/
|
||||||
|
Integer[] getHierarchyDescription(T id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns level of the node.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* id of the node
|
||||||
|
* @return level in the tree
|
||||||
|
*/
|
||||||
|
int getLevel(T id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns information about the node.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* node id
|
||||||
|
* @return node info
|
||||||
|
*/
|
||||||
|
TreeNodeInfo<T> getNodeInfo(T id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns children of the node.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* id of the node or null if asking for top nodes
|
||||||
|
* @return children of the node
|
||||||
|
*/
|
||||||
|
List<T> getChildren(T id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns parent of the node.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* id of the node
|
||||||
|
* @return parent id or null if no parent
|
||||||
|
*/
|
||||||
|
T getParent(T id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the node before child or at the beginning.
|
||||||
|
*
|
||||||
|
* @param parent
|
||||||
|
* id of the parent node. If null - adds at the top level
|
||||||
|
* @param newChild
|
||||||
|
* new child to add if null - adds at the beginning.
|
||||||
|
* @param beforeChild
|
||||||
|
* child before which to add the new child
|
||||||
|
*/
|
||||||
|
void addBeforeChild(T parent, T newChild, T beforeChild);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the node after child or at the end.
|
||||||
|
*
|
||||||
|
* @param parent
|
||||||
|
* id of the parent node. If null - adds at the top level.
|
||||||
|
* @param newChild
|
||||||
|
* new child to add. If null - adds at the end.
|
||||||
|
* @param afterChild
|
||||||
|
* child after which to add the new child
|
||||||
|
*/
|
||||||
|
void addAfterChild(T parent, T newChild, T afterChild);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the node and all children from the tree.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* id of the node to remove or null if all nodes are to be
|
||||||
|
* removed.
|
||||||
|
*/
|
||||||
|
void removeNodeRecursively(T id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expands all children of the node.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* node which children should be expanded. cannot be null (top
|
||||||
|
* nodes are always expanded!).
|
||||||
|
*/
|
||||||
|
void expandDirectChildren(T id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expands everything below the node specified. Might be null - then expands
|
||||||
|
* all.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* node which children should be expanded or null if all nodes
|
||||||
|
* are to be expanded.
|
||||||
|
*/
|
||||||
|
void expandEverythingBelow(T id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collapse children.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* id collapses everything below node specified. If null,
|
||||||
|
* collapses everything but top-level nodes.
|
||||||
|
*/
|
||||||
|
void collapseChildren(T id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns next sibling of the node (or null if no further sibling).
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* node id
|
||||||
|
* @return the sibling (or null if no next)
|
||||||
|
*/
|
||||||
|
T getNextSibling(T id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns previous sibling of the node (or null if no previous sibling).
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* node id
|
||||||
|
* @return the sibling (or null if no previous)
|
||||||
|
*/
|
||||||
|
T getPreviousSibling(T id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if given node is already in tree.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* id of the node
|
||||||
|
* @return true if node is already in tree.
|
||||||
|
*/
|
||||||
|
boolean isInTree(T id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count visible elements.
|
||||||
|
*
|
||||||
|
* @return number of currently visible elements.
|
||||||
|
*/
|
||||||
|
int getVisibleCount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns visible node list.
|
||||||
|
*
|
||||||
|
* @return return the list of all visible nodes in the right sequence
|
||||||
|
*/
|
||||||
|
List<T> getVisibleList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers observers with the manager.
|
||||||
|
*
|
||||||
|
* @param observer
|
||||||
|
* observer
|
||||||
|
*/
|
||||||
|
void registerDataSetObserver(final DataSetObserver observer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters observers with the manager.
|
||||||
|
*
|
||||||
|
* @param observer
|
||||||
|
* observer
|
||||||
|
*/
|
||||||
|
void unregisterDataSetObserver(final DataSetObserver observer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans tree stored in manager. After this operation the tree is empty.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refreshes views connected to the manager.
|
||||||
|
*/
|
||||||
|
void refresh();
|
||||||
|
}
|
@ -0,0 +1,198 @@
|
|||||||
|
package pl.polidea.treeview;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.ListAdapter;
|
||||||
|
import android.widget.ListView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tree view, expandable multi-level.
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* attr ref pl.polidea.treeview.R.styleable#TreeViewList_collapsible
|
||||||
|
* attr ref pl.polidea.treeview.R.styleable#TreeViewList_src_expanded
|
||||||
|
* attr ref pl.polidea.treeview.R.styleable#TreeViewList_src_collapsed
|
||||||
|
* attr ref pl.polidea.treeview.R.styleable#TreeViewList_indent_width
|
||||||
|
* attr ref pl.polidea.treeview.R.styleable#TreeViewList_handle_trackball_press
|
||||||
|
* attr ref pl.polidea.treeview.R.styleable#TreeViewList_indicator_gravity
|
||||||
|
* attr ref pl.polidea.treeview.R.styleable#TreeViewList_indicator_background
|
||||||
|
* attr ref pl.polidea.treeview.R.styleable#TreeViewList_row_background
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public class TreeViewList extends ListView {
|
||||||
|
private static final int DEFAULT_COLLAPSED_RESOURCE = R.drawable.collapsed;
|
||||||
|
private static final int DEFAULT_EXPANDED_RESOURCE = R.drawable.expanded;
|
||||||
|
private static final int DEFAULT_INDENT = 0;
|
||||||
|
private static final int DEFAULT_GRAVITY = Gravity.LEFT
|
||||||
|
| Gravity.CENTER_VERTICAL;
|
||||||
|
private Drawable expandedDrawable;
|
||||||
|
private Drawable collapsedDrawable;
|
||||||
|
private Drawable rowBackgroundDrawable;
|
||||||
|
private Drawable indicatorBackgroundDrawable;
|
||||||
|
private int indentWidth = 0;
|
||||||
|
private int indicatorGravity = 0;
|
||||||
|
private AbstractTreeViewAdapter< ? > treeAdapter;
|
||||||
|
private boolean collapsible;
|
||||||
|
private boolean handleTrackballPress;
|
||||||
|
|
||||||
|
public TreeViewList(final Context context, final AttributeSet attrs) {
|
||||||
|
this(context, attrs, R.style.treeViewListStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TreeViewList(final Context context) {
|
||||||
|
this(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TreeViewList(final Context context, final AttributeSet attrs,
|
||||||
|
final int defStyle) {
|
||||||
|
super(context, attrs, defStyle);
|
||||||
|
parseAttributes(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseAttributes(final Context context, final AttributeSet attrs) {
|
||||||
|
final TypedArray a = context.obtainStyledAttributes(attrs,
|
||||||
|
R.styleable.TreeViewList);
|
||||||
|
expandedDrawable = a.getDrawable(R.styleable.TreeViewList_src_expanded);
|
||||||
|
if (expandedDrawable == null) {
|
||||||
|
expandedDrawable = context.getResources().getDrawable(
|
||||||
|
DEFAULT_EXPANDED_RESOURCE);
|
||||||
|
}
|
||||||
|
collapsedDrawable = a
|
||||||
|
.getDrawable(R.styleable.TreeViewList_src_collapsed);
|
||||||
|
if (collapsedDrawable == null) {
|
||||||
|
collapsedDrawable = context.getResources().getDrawable(
|
||||||
|
DEFAULT_COLLAPSED_RESOURCE);
|
||||||
|
}
|
||||||
|
indentWidth = a.getDimensionPixelSize(
|
||||||
|
R.styleable.TreeViewList_indent_width, DEFAULT_INDENT);
|
||||||
|
indicatorGravity = a.getInteger(
|
||||||
|
R.styleable.TreeViewList_indicator_gravity, DEFAULT_GRAVITY);
|
||||||
|
indicatorBackgroundDrawable = a
|
||||||
|
.getDrawable(R.styleable.TreeViewList_indicator_background);
|
||||||
|
rowBackgroundDrawable = a
|
||||||
|
.getDrawable(R.styleable.TreeViewList_row_background);
|
||||||
|
collapsible = a.getBoolean(R.styleable.TreeViewList_collapsible, true);
|
||||||
|
handleTrackballPress = a.getBoolean(
|
||||||
|
R.styleable.TreeViewList_handle_trackball_press, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAdapter(final ListAdapter adapter) {
|
||||||
|
if (!(adapter instanceof AbstractTreeViewAdapter)) {
|
||||||
|
throw new TreeConfigurationException(
|
||||||
|
"The adapter is not of TreeViewAdapter type");
|
||||||
|
}
|
||||||
|
treeAdapter = (AbstractTreeViewAdapter< ? >) adapter;
|
||||||
|
syncAdapter();
|
||||||
|
super.setAdapter(treeAdapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void syncAdapter() {
|
||||||
|
treeAdapter.setCollapsedDrawable(collapsedDrawable);
|
||||||
|
treeAdapter.setExpandedDrawable(expandedDrawable);
|
||||||
|
treeAdapter.setIndicatorGravity(indicatorGravity);
|
||||||
|
treeAdapter.setIndentWidth(indentWidth);
|
||||||
|
treeAdapter.setIndicatorBackgroundDrawable(indicatorBackgroundDrawable);
|
||||||
|
treeAdapter.setRowBackgroundDrawable(rowBackgroundDrawable);
|
||||||
|
treeAdapter.setCollapsible(collapsible);
|
||||||
|
if (handleTrackballPress) {
|
||||||
|
setOnItemClickListener(new OnItemClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onItemClick(final AdapterView< ? > parent,
|
||||||
|
final View view, final int position, final long id) {
|
||||||
|
treeAdapter.handleItemClick(view, view.getTag());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setOnClickListener(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpandedDrawable(final Drawable expandedDrawable) {
|
||||||
|
this.expandedDrawable = expandedDrawable;
|
||||||
|
syncAdapter();
|
||||||
|
treeAdapter.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCollapsedDrawable(final Drawable collapsedDrawable) {
|
||||||
|
this.collapsedDrawable = collapsedDrawable;
|
||||||
|
syncAdapter();
|
||||||
|
treeAdapter.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRowBackgroundDrawable(final Drawable rowBackgroundDrawable) {
|
||||||
|
this.rowBackgroundDrawable = rowBackgroundDrawable;
|
||||||
|
syncAdapter();
|
||||||
|
treeAdapter.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIndicatorBackgroundDrawable(
|
||||||
|
final Drawable indicatorBackgroundDrawable) {
|
||||||
|
this.indicatorBackgroundDrawable = indicatorBackgroundDrawable;
|
||||||
|
syncAdapter();
|
||||||
|
treeAdapter.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIndentWidth(final int indentWidth) {
|
||||||
|
this.indentWidth = indentWidth;
|
||||||
|
syncAdapter();
|
||||||
|
treeAdapter.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIndicatorGravity(final int indicatorGravity) {
|
||||||
|
this.indicatorGravity = indicatorGravity;
|
||||||
|
syncAdapter();
|
||||||
|
treeAdapter.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCollapsible(final boolean collapsible) {
|
||||||
|
this.collapsible = collapsible;
|
||||||
|
syncAdapter();
|
||||||
|
treeAdapter.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHandleTrackballPress(final boolean handleTrackballPress) {
|
||||||
|
this.handleTrackballPress = handleTrackballPress;
|
||||||
|
syncAdapter();
|
||||||
|
treeAdapter.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Drawable getExpandedDrawable() {
|
||||||
|
return expandedDrawable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Drawable getCollapsedDrawable() {
|
||||||
|
return collapsedDrawable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Drawable getRowBackgroundDrawable() {
|
||||||
|
return rowBackgroundDrawable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Drawable getIndicatorBackgroundDrawable() {
|
||||||
|
return indicatorBackgroundDrawable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndentWidth() {
|
||||||
|
return indentWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndicatorGravity() {
|
||||||
|
return indicatorGravity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCollapsible() {
|
||||||
|
return collapsible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHandleTrackballPress() {
|
||||||
|
return handleTrackballPress;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
This is a small utility that provides quite configurable tree view list.
|
||||||
|
It is based on standard android list view. It separates out different
|
||||||
|
aspects of the tree: there is a separate list view, tree adapter, tree
|
||||||
|
state manager and tree state builder.
|
||||||
|
<p>
|
||||||
|
<ul>
|
||||||
|
<li>Tree view provides the frame to display the view.</li>
|
||||||
|
<li>Adapter allows to create visual representation of each tree
|
||||||
|
node.</li>
|
||||||
|
<li>State manager provides storage for tree state (connections
|
||||||
|
between parents and children, collapsed/expanded state). It provides
|
||||||
|
all the low-level tree manipulation methods.</li>
|
||||||
|
<li>Tree builder allows to build tree easily providing higher
|
||||||
|
level methods. The tree can be build either from prepared sequentially
|
||||||
|
prepared list of nodes (node id, level) or using (parent/child
|
||||||
|
relationships).</li>
|
||||||
|
<p>For now only in-memory state manager is provided, but Tree State
|
||||||
|
Manger interface is done in the way that database tree manager even for
|
||||||
|
large trees is potentially supported.
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,4 @@
|
|||||||
|
/**
|
||||||
|
* Provides expandable Tree View implementation.
|
||||||
|
*/
|
||||||
|
package pl.polidea.treeview;
|