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;
|