Is it possible to add a CheckBoxField to a TreeField in BlackBerry ?
If yes, how do I do it?
Same trick as with ListBox CheckBoxes:
alt text http://img441.imageshack.us/img441/5120/checkboxtree.jpg
class CBTreeField extends VerticalFieldManager implements TreeFieldCallback,
DrawStyle {
boolean[] mBooleanValues = new boolean[] {};
String[] mStringValues = new String[] {};
public boolean getNodeBooleanValue(int node) {
return mBooleanValues[node];
}
public void setNodeBooleanValue(int node, boolean value) {
mBooleanValues[node] = value;
}
TreeField mRootField = null;
public CBTreeField(String rootString, boolean rootBoolean) {
mRootField = new TreeField(this, TreeField.FOCUSABLE);
add(mRootField);
mStringValues = insertAt(mStringValues, 0, rootString);
mBooleanValues = insertAt(mBooleanValues, 0, rootBoolean);
}
public int addSiblingNode(int previousSibling, String stringValue,
boolean booleanValue, Object cookie) {
int index = mRootField.addSiblingNode(previousSibling, cookie);
mBooleanValues = insertAt(mBooleanValues, index, booleanValue);
mStringValues = insertAt(mStringValues, index, stringValue);
return index;
}
public int addChildNode(int parent, String stringValue,
boolean booleanValue, Object cookie) {
int index = mRootField.addChildNode(parent, cookie);
mBooleanValues = insertAt(mBooleanValues, index, booleanValue);
mStringValues = insertAt(mStringValues, index, stringValue);
return index;
}
static boolean[] insertAt(boolean[] inArray, int index, boolean value) {
int newLen = inArray.length + 1;
boolean[] outArray = new boolean[newLen];
for (int i = 0, j = 0; i < newLen; i++, j++) {
outArray[i] = (i != index) ? inArray[j] : value;
if (i == index)
j++;
}
return outArray;
}
static String[] insertAt(String[] inArray, int index, String value) {
int newLen = inArray.length + 1;
String[] outArray = new String[newLen];
for (int i = 0, j = 0; i < newLen; i++, j++) {
outArray[i] = (i != index) ? inArray[j] : value;
if (i == index)
j++;
}
return outArray;
}
public void drawTreeItem(TreeField treeField, Graphics g, int node, int y,
int width, int indent) {
String check = String
.valueOf(mBooleanValues[node] ?
Characters.BALLOT_BOX_WITH_CHECK : Characters.BALLOT_BOX);
g.drawText(check, indent, y, DrawStyle.LEFT);
g.drawText(mStringValues[node], indent + 20, y, DrawStyle.RIGHT
| ELLIPSIS);
}
protected void makeMenu(Menu menu, int instance) {
super.makeMenu(menu, instance);
menu.add(new MenuItem("Change value", 0, 0) {
public void run() {
int node = mRootField.getCurrentNode();
mBooleanValues[node] = !mBooleanValues[node];
invalidate();
}
});
}
}
sample of use:
class Scr extends MainScreen {
public Scr() {
CBTreeField tree = new CBTreeField("root", false);
add(tree);
int ch01 = tree.addChildNode(0, "child 0-1", true, null);
int ch02 = tree.addChildNode(0, "child 0-2", false, null);
int ch03 = tree.addChildNode(0, "child 0-3", false, null);
int ch011 = tree.addChildNode(ch01, "child 0-1-1", false, null);
int ch012 = tree.addChildNode(ch01, "child 0-1-2", true, null);
int ch031 = tree.addChildNode(ch03, "child 0-3-1", true, null);
}
}
Related
Given Parent Array Such that parent[i]=j where j is the parent and Value array . Need to Find Best possible sum.
Root node will have -1 as parent.
Best Possible sum is maximum sum in one of the tree paths.
Ex)
Integer[] parent = new Integer[] { -1, 0, 0, 2, 3 };
Integer[] values = new Integer[] { 0, 4, 6, -11, 3 };
(0/0)----(1/4)
|
|
(2/6)
|
|
(3/-11)
|
|
(4/3)
Maximum sum here would be 6+0+4=10 for path 2-->0-->1.
I have tried solving it the dfs way. But not sure if it works for all cases. Below is my code. It gives all possible sum. we can take out max from that.
package com.programs.algo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class BestPossibleSum {
static class Node<T> {
T label;
T data;
List<Node<T>> nodes;
}
public static void main(String[] args) {
Integer[] parent = new Integer[] { -1, 0, 0, 1, 1, 3, 5 };
Integer[] values = new Integer[] { 0, 4, 6, -11, 3, 10, 11 };
List<Integer> list1 = new ArrayList<>(Arrays.asList(parent));
List<Integer> list2 = new ArrayList<>(Arrays.asList(values));
bestPossibleSum(list1, list2);
}
static List<Node<Integer>> tree = new ArrayList<>();
private static void bestPossibleSum(List<Integer> list1, List<Integer> list2) {
int adj[][] = new int[list1.size()][list1.size()];
createTree(list1, list2, adj);
List<Integer> traversedNodes = new ArrayList<>();
List<Integer> sumOfraversedNodes = new ArrayList<>();
for (int i = 0; i < adj.length; i++) {
dfs(tree.get(i), traversedNodes, sumOfraversedNodes);
traversedNodes.clear();
}
System.out.println(sumOfraversedNodes);
}
private static void dfs(Node<Integer> tree, List<Integer> traversedNodes, List<Integer> sums) {
if (!traversedNodes.contains(tree.label)) {
traversedNodes.add(tree.label);
sums.add(getSum(traversedNodes));
for (Node<Integer> child : tree.nodes) {
dfs(child, traversedNodes, sums);
}
}
}
private static Integer getSum(List<Integer> traversedNodes) {
System.out.println(traversedNodes);
return traversedNodes.stream().reduce(0, Integer::sum);
}
private static void createTree(List<Integer> parent, List<Integer> values, int[][] adj) {
for (int i = 0; i < parent.size(); i++) {
Node<Integer> node = new Node<>();
node.label = i;
node.data = values.get(i);
node.nodes = new ArrayList<>();
tree.add(i, node);
}
for (int i = 0; i < parent.size(); i++) {
if (parent.get(i) != -1) {
adj[parent.get(i)][i] = 1;
adj[i][parent.get(i)] = 1;
tree.get(parent.get(i)).nodes.add(tree.get(i));
}
}
tree.forEach(t -> {
System.out.println(t.label);
System.out.println(t.nodes.stream().map(m -> m.label).collect(Collectors.toList()));
});
// System.out.println(Arrays.deepToString(adj));
}
}
I would divide your question to 2 different issues:
Build tree from your data
Find the max sum
I wrote the code in PHP but you can convert it to any language you need (my JAVA skill are bit rusty...)
Build the Tree:
$parent = array( -1, 0, 0, 2, 3 );
$values = array(0, 4, 6, -11, 3 );
function getNode($id, $data) {
return array("id" => $id, "data" => $data, "childs" => array());
}
function addToTree($node, &$root, $parentsId) {
if ($parentsId == -1)
$root = $node;
else if ( $root["id"] == $parentsId)
$root["childs"][] = $node;
else
foreach($root["childs"] as &$child)
addToTree($node, $child, $parentsId);
}
$root = null;
for($i = 0; $i < count($parent); $i++) {
addToTree(getNode($i, $values[$i]), $root, $parent[$i]);
}
Now root if contain you "tree-like" data. Notice this code works only if the nodes given at the right order and it cannot support multi root (assume tree and not forest)
Find max path:
function maxPath($node) {
$sum = $node["data"];
foreach($node["childs"] as $child) {
$s = maxPath($child);
if ($s > 0) // if its not positive then don't take it
$sum += $s;
}
return $sum;
}
This recursive function will get your max-sum-path. Notice this will allow multi-child per node and also the path can have star-shape.
Posting Java code considering it as tree with left and right nodes.
https://www.geeksforgeeks.org/construct-a-binary-tree-from-parent-array-representation/
https://www.geeksforgeeks.org/find-maximum-path-sum-in-a-binary-tree/
private static int maxSum(Node<Integer> btree, Result result) {
if (btree == null)
return 0;
int l = maxSum(btree.left, result);
int r = maxSum(btree.right, result);
System.out.println(l + " " + r + " " + btree.data);
int maxSingle = Math.max(Math.max(l, r) + btree.label, btree.label);
int maxTop = Math.max(l + r + btree.label, maxSingle);
result.val = Math.max(maxTop, result.val);
return maxSingle;
}
private static Node<Integer> createBinaryTree(Integer[] parent, Node<Integer> root) {
Map<Integer, Node<Integer>> map = new HashMap<>();
for (int i = 0; i < parent.length; i++) {
map.put(i, new Node<>(i));
}
for (int i = 0; i < parent.length; i++) {
if (parent[i] == -1) {
root = map.get(i);
} else {
Node<Integer> par = map.get(parent[i]);
Node<Integer> child = map.get(i);
if (par.left == null) {
par.left = child;
} else {
par.right = child;
}
}
}
return root;
}
1 . convert the given parent array into graph with the following steps :
unordered_map<int,vector<pair<int,int>>> graph;
for(int i=0;i<n;i++){
if(parents[i]!=-1){
graph[parents[i]].push_back({i,values[i]});
graph[i].push_back({parents[i],values[parents[i]]});
}
}
2.apply DFS on each node and check the maximum Path Sum
vector<bool> vis(n,false);
int res=0;
for(int i=0;i<n;i++){
vis.clear();
dfs(i,vis,mp,values,res);
}
DFS function
void dfs(int src,vector&vis,unordered_map<int,
vector<pair<int,int>>>&graph,vector<int>&values,int res){
res+=values[src];
ans=max(ans,res);
vis[src]=true;
for(int i=0;i<graph[src].size();i++){
if(!vis[graph[src][i].first]){
dfs(graph[src][i].first,vis,graph,values,res);
}
}
vis[src]=false;
}
C++ code :
#include<bits/stdc++.h>
using namespace std;
int ans=INT_MIN;
void dfs(int src,vector<bool>&vis,unordered_map<int,
vector<pair<int,int>>>&graph,vector<int>&values,int res){
res+=values[src];
ans=max(ans,res);
vis[src]=true;
for(int i=0;i<graph[src].size();i++){
if(!vis[graph[src][i].first]){
dfs(graph[src][i].first,vis,graph,values,res);
}
}
vis[src]=false;
}
int maxPathSum(vector<int>&parents,vector<int>&values){
int n=parents.size();
unordered_map<int,vector<pair<int,int>>> mp;
for(int i=0;i<n;i++){
if(parents[i]!=-1){
mp[parents[i]].push_back({i,values[i]});
mp[i].push_back({parents[i],values[parents[i]]});
}
}
vector<bool> vis(n,false);
int res=0;
for(int i=0;i<n;i++){
vis.clear();
dfs(i,vis,mp,values,res);
}
return ans;
}
int main(){
vector<int> parent = {-1,0,0,2,3}; //{-1,0,1,2,0};
vector<int> values = {0,4,6,-11,3}; //{-2,10,10,-3,10};
cout<<maxPathSum(parent,values)<<endl;
return 0;
}
Today I got this problem in One of the company's hackerrank test.
Here is my solution. All test cases have been passed successfully
import java.io.*;
import java.math.*;
import java.security.*;
import java.text.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.*;
import java.util.regex.*;
import java.util.stream.*;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
class Result {
/*
* Complete the 'bestSumDownwardTreePath' function below.
*
* The function is expected to return an INTEGER.
* The function accepts following parameters:
* 1. INTEGER_ARRAY parent
* 2. INTEGER_ARRAY values
*/
static int bestPath = Integer.MIN_VALUE;
public static int bestSumDownwardTreePath(List<Integer> parent, List<Integer> values) {
if(parent.size() == 1) return values.get(0);
Map<Integer, List<Integer>> tree = new HashMap<>();
for(int i = 1; i < parent.size(); i++) {
List<Integer> temp = tree.getOrDefault(parent.get(i), null);
if(temp == null) {
temp = new ArrayList<>();
temp.add(i);
tree.put(parent.get(i), temp);
}
else {
temp.add(i);
}
}
findBestSum(parent, values, tree, 0, 0);
return bestPath;
}
public static void findBestSum(List<Integer> parent, List<Integer> values,
Map<Integer, List<Integer>> tree, int root, int sum) {
sum = sum + values.get(root);
bestPath = Math.max(bestPath, sum);
sum = Math.max(0, sum);
if(tree.get(root) == null) return;
for(Integer child: tree.get(root)) {
findBestSum(parent, values, tree, child, sum);
}
}
}
public class Solution {
public static void main(String[] args) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(System.getenv("OUTPUT_PATH")));
int parentCount = Integer.parseInt(bufferedReader.readLine().trim());
List<Integer> parent = IntStream.range(0, parentCount).mapToObj(i -> {
try {
return bufferedReader.readLine().replaceAll("\\s+$", "");
} catch (IOException ex) {
throw new RuntimeException(ex);
}
})
.map(String::trim)
.map(Integer::parseInt)
.collect(toList());
int valuesCount = Integer.parseInt(bufferedReader.readLine().trim());
List<Integer> values = IntStream.range(0, valuesCount).mapToObj(i -> {
try {
return bufferedReader.readLine().replaceAll("\\s+$", "");
} catch (IOException ex) {
throw new RuntimeException(ex);
}
})
.map(String::trim)
.map(Integer::parseInt)
.collect(toList());
int result = Result.bestSumDownwardTreePath(parent, values);
bufferedWriter.write(String.valueOf(result));
bufferedWriter.newLine();
bufferedReader.close();
bufferedWriter.close();
}
}
I'm not sure where to start, but this is messy. Basically I need to write an Insertion Sort method for singly linked list - which causes enough problems, because usually for Insertion Sort - you're supposed to go through array/list elements backwards - which implementing into a singly linked list seems pointless, because the point of it - is that you're only capable of going forwards in the list and in addition to that -> I need to execute "swap" operations externally, which I do not completely understand how to perform that while using list structure.
This is my ArrayClass and Swap method that I used:
class MyFileArray : DataArray
{
public MyFileArray(string filename, int n, int seed)
{
double[] data = new double[n];
length = n;
Random rand = new Random(seed);
for (int i = 0; i < length; i++)
{
data[i] = rand.NextDouble();
}
if (File.Exists(filename)) File.Delete(filename);
try
{
using (BinaryWriter writer = new BinaryWriter(File.Open(filename,
FileMode.Create)))
{
for (int j = 0; j < length; j++)
writer.Write(data[j]);
}
}
catch (IOException ex)
{
Console.WriteLine(ex.ToString());
}
}
public FileStream fs { get; set; }
public override double this[int index]
{
get
{
Byte[] data = new Byte[8];
fs.Seek(8 * index, SeekOrigin.Begin);
fs.Read(data, 0, 8);
double result = BitConverter.ToDouble(data, 0);
return result;
}
}
public override void Swap(int j, double a)
{
Byte[] data = new Byte[16];
BitConverter.GetBytes(a).CopyTo(data, 0);
fs.Seek(8 * (j + 1), SeekOrigin.Begin);
fs.Write(data, 0, 8);
}
}
And this is my Insertion Sort for array:
public static void InsertionSort(DataArray items)
{
double key;
int j;
for (int i = 1; i < items.Length; i++)
{
key = items[i];
j = i - 1;
while (j >= 0 && items[j] > key)
{
items.Swap(j, items[j]);
j = j - 1;
}
items.Swap(j, key);
}
}
Now I somehow have to do the same exact thing - however using Singly Linked List, I'm given this kind of class to work with (allowed to make changes):
class MyFileList : DataList
{
int prevNode;
int currentNode;
int nextNode;
public MyFileList(string filename, int n, int seed)
{
length = n;
Random rand = new Random(seed);
if (File.Exists(filename)) File.Delete(filename);
try
{
using (BinaryWriter writer = new BinaryWriter(File.Open(filename,
FileMode.Create)))
{
writer.Write(4);
for (int j = 0; j < length; j++)
{
writer.Write(rand.NextDouble());
writer.Write((j + 1) * 12 + 4);
}
}
}
catch (IOException ex)
{
Console.WriteLine(ex.ToString());
}
}
public FileStream fs { get; set; }
public override double Head()
{
Byte[] data = new Byte[12];
fs.Seek(0, SeekOrigin.Begin);
fs.Read(data, 0, 4);
currentNode = BitConverter.ToInt32(data, 0);
prevNode = -1;
fs.Seek(currentNode, SeekOrigin.Begin);
fs.Read(data, 0, 12);
double result = BitConverter.ToDouble(data, 0);
nextNode = BitConverter.ToInt32(data, 8);
return result;
}
public override double Next()
{
Byte[] data = new Byte[12];
fs.Seek(nextNode, SeekOrigin.Begin);
fs.Read(data, 0, 12);
prevNode = currentNode;
currentNode = nextNode;
double result = BitConverter.ToDouble(data, 0);
nextNode = BitConverter.ToInt32(data, 8);
return result;
}
To be completely honest - I'm not sure neither how I'm supposed to implement Insertion Sort nor How then translate it into an external sort. I've used this code for not external sorting previously:
public override void InsertionSort()
{
sorted = null;
MyLinkedListNode current = headNode;
while (current != null)
{
MyLinkedListNode next = current.nextNode;
sortedInsert(current);
current = next;
}
headNode = sorted;
}
void sortedInsert(MyLinkedListNode newnode)
{
if (sorted == null || sorted.data >= newnode.data)
{
newnode.nextNode = sorted;
sorted = newnode;
}
else
{
MyLinkedListNode current = sorted;
while (current.nextNode != null && current.nextNode.data < newnode.data)
{
current = current.nextNode;
}
newnode.nextNode = current.nextNode;
current.nextNode = newnode;
}
}
So if someone could maybe give some kind of tips/explanations - or maybe if you have ever tried this - code examples how to solve this kind of problem, would be appreciated!
I actually have solved this fairly recently.
Here's the code sample that you can play around with, it should work out of the box.
public class SortLinkedList {
public static class LinkListNode {
private Integer value;
LinkListNode nextNode;
public LinkListNode(Integer value, LinkListNode nextNode) {
this.value = value;
this.nextNode = nextNode;
}
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
public LinkListNode getNextNode() {
return nextNode;
}
public void setNextNode(LinkListNode nextNode) {
this.nextNode = nextNode;
}
#Override
public String toString() {
return this.value.toString();
}
}
public static void main(String...args) {
LinkListNode f = new LinkListNode(12, null);
LinkListNode e = new LinkListNode(11, f);
LinkListNode c = new LinkListNode(13, e);
LinkListNode b = new LinkListNode(1, c);
LinkListNode a = new LinkListNode(5, b);
print(sort(a));
}
public static void print(LinkListNode aList) {
LinkListNode iterator = aList;
while (iterator != null) {
System.out.println(iterator.getValue());
iterator = iterator.getNextNode();
}
}
public static LinkListNode sort(LinkListNode aList){
LinkListNode head = new LinkListNode(null, aList);
LinkListNode fringePtr = aList.getNextNode();
LinkListNode ptrBeforeFringe = aList;
LinkListNode findPtr;
LinkListNode prev;
while(fringePtr != null) {
Integer valueToInsert = fringePtr.getValue();
findPtr = head.getNextNode();
prev = head;
while(findPtr != fringePtr) {
System.out.println("fringe=" + fringePtr);
System.out.println(findPtr);
if (valueToInsert <= findPtr.getValue()) {
LinkListNode tmpNode = fringePtr.getNextNode();
fringePtr.setNextNode(findPtr);
prev.setNextNode(fringePtr);
ptrBeforeFringe.setNextNode(tmpNode);
fringePtr = ptrBeforeFringe;
break;
}
findPtr = findPtr.getNextNode();
prev = prev.getNextNode();
}
fringePtr = fringePtr.getNextNode();
if (ptrBeforeFringe.getNextNode() != fringePtr) {
ptrBeforeFringe = ptrBeforeFringe.getNextNode();
}
}
return head.getNextNode();
}
}
From a high level, what you are doing is you are keeping track of a fringe ptr, and you are inserting a node s.t. the it is in the correct spot in the corresponding sublist.
For instance, suppose I have this LL.
3->2->5->4
The first iteration, I have fringePtr at 2, and I want to insert 2 somewhere in the sublist that's before the fringe ptr, so I basically traverse starting from head going to the fringe ptr until the value is less than the current value. I also have a previous keeping track of the previous ptr (to account for null, I have a sentinel node at the start of my traversal so I can insert it at the head).
Then, when I see that it's less than the current, I know I need to insert it next to the previous, so I have to:
use a temporary ptr to keep track of my previous's current next.
bind previuos's next to my toInsert node.
bind my toInsert node's next to my temp node.
Then, to continue, you just advance your fringe ptr and try again, basically building up a sublist that is sorted as you move along until fringe hits the end.
i.e. the iterations will look like
1. 3->2->5->4
^
2. 2->3->5->4
^
3. 2->3->5->4
^
4. 2->3->4->5 FIN.
I'm having an interesting anomaly when displaying a listfield on the blackberry simulator:
The top item is the height of a single line of text (about 12 pixels) while the rest are fine.
Does anyone know why only the top item is being drawn this way? Also, when I add an empty venue in position 0, it still displays the first actual venue this way (item in position 1).
Not sure what to do.
Thanks for any help.
The layout looks like this:
-----------------------------------
| *part of image* | title |
-----------------------------------
| | title |
| * full image * | address |
| | city, zip |
-----------------------------------
The object is called like so:
listField = new ListField( venueList.size() );
listField.setCallback( this );
listField.setSelectedIndex(-1);
_middle.add( listField );
Here is the drawListRow code:
public void drawListRow( ListField listField, Graphics graphics,
int index, int y, int width )
{
listField.setRowHeight(90);
Hashtable item = (Hashtable) venueList.elementAt( index );
String venue_name = (String) item.get("name");
String image_url = (String) item.get("image_url");
String address = (String) item.get("address");
String city = (String) item.get("city");
String zip = (String) item.get("zip");
EncodedImage img = null;
try
{
String filename = image_url.substring(image_url.indexOf("crop/")
+ 5, image_url.length() );
FileConnection fconn = (FileConnection)Connector.open(
"file:///SDCard/Blackberry/project1/" + filename,
Connector.READ);
if ( !fconn.exists() )
{
}
else
{
InputStream input = fconn.openInputStream();
byte[] data = new byte[(int)fconn.fileSize()];
input.read(data);
input.close();
if(data.length > 0)
{
EncodedImage rawimg = EncodedImage.createEncodedImage(
data, 0, data.length);
int dw = Fixed32.toFP(Display.getWidth());
int iw = Fixed32.toFP(rawimg.getWidth());
int sf = Fixed32.div(iw, dw);
img = rawimg.scaleImage32(sf * 4, sf * 4);
}
else
{
}
}
}
catch(IOException ef)
{
}
graphics.drawText( venue_name, 140, y, 0, width );
graphics.drawText( address, 140, y + 15, 0, width );
graphics.drawText( city + ", " + zip, 140, y + 30, 0, width );
if(img != null)
{
graphics.drawImage(0, y, img.getWidth(), img.getHeight(),
img, 0, 0, 0);
}
}
setRowHeight should be called once after construction of ListField, not inside of drawListRow on each time row is repainted:
listField = new ListField( venueList.size() );
listField.setRowHeight(90);
listField.setCallback( this );
listField.setSelectedIndex(-1);
_middle.add( listField );
Aman,
Hopefully you can use this for something. You should be able to extract the list field data from this wildly out of control class. Remember, this is a work in progress, so you will have to strip out the things that are quite clearly custom to my app. Like the image handling that relies on a substring for a file name.
It works fine for me, but it will totally not work for anyone htat just copies and pastes, so good luck...
package venue;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;
import net.rim.device.api.math.Fixed32;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.Display;
import net.rim.device.api.system.EncodedImage;
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.FocusChangeListener;
import net.rim.device.api.ui.Font;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.Screen;
import net.rim.device.api.ui.Ui;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.BitmapField;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.ListField;
import net.rim.device.api.ui.component.ListFieldCallback;
import net.rim.device.api.ui.component.Menu;
import net.rim.device.api.ui.component.RichTextField;
import net.rim.device.api.ui.component.SeparatorField;
import net.rim.device.api.ui.container.HorizontalFieldManager;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.container.VerticalFieldManager;
public class categoryView extends MainScreen implements FieldChangeListener, ListFieldCallback, FocusChangeListener {
private HorizontalFieldManager _top;
private HorizontalFieldManager _nav;
private VerticalFieldManager _middle;
private int horizontalOffset;
private final static long animationTime = 300;
private long animationStart = 0;
private int venue_id;
private int category_id;
private CustomButtonField rectangle;
private Vector venueList = new Vector();
private Hashtable venue_index = new Hashtable();
private Vector image_index = new Vector();
private ListField listField;
private int last_menu_item = 2;
private int last_nav = 2;
private int before_last = 1;
private int location_count = 0;
private int img_width = 120;
private int img_height = 80;
private Field f;
public categoryView(int id) {
super();
category_id = id;
horizontalOffset = Display.getWidth();
_top = new HorizontalFieldManager(Manager.USE_ALL_WIDTH | Field.FIELD_HCENTER)
{
public void paint(Graphics gr)
{
Bitmap bg = Bitmap.getBitmapResource("bg.png");
gr.drawBitmap(0, 0, Display.getWidth(), Display.getHeight(), bg, 0, 0);
subpaint(gr);
}
};
_nav = new HorizontalFieldManager(Field.USE_ALL_WIDTH);
_middle = new VerticalFieldManager();
add(_top);
add(_nav);
add(_middle);
Bitmap lol = Bitmap.getBitmapResource("logo.png");
BitmapField lolfield = new BitmapField(lol);
_top.add(lolfield);
HorizontalFieldManager nav = new HorizontalFieldManager(Field.USE_ALL_WIDTH | Manager.HORIZONTAL_SCROLL);
Vector locs = getLocations();
Hashtable locations = (Hashtable) locs.elementAt(0);
Enumeration ne = locations.keys();
Enumeration nv = locations.elements();
int counter = 1;
if(locations.size() > 1)
{
counter = locations.size() - 1;
}
int count = 1;
while(ne.hasMoreElements())
{
final String location_id = ne.nextElement().toString();
String location = nv.nextElement().toString();
last_nav = Integer.parseInt(location_id);
rectangle = new CustomButtonField(location_id, location, 25, Field.FOCUSABLE);
rectangle.setFocusListener(this);
nav.add(rectangle);
if(count == counter)
{
before_last = Integer.parseInt(location_id);
}
count ++;
}
_nav.add(nav);
}
public void setDefaultLocation()
{
Vector locs = getLocations();
Hashtable loc1 = (Hashtable) locs.elementAt(0);
Enumeration er = loc1.keys();
Enumeration vr = loc1.elements();
int i = 0;
while(er.hasMoreElements())
{
final String location_id = er.nextElement().toString();
if(i == 0)
{
last_menu_item = Integer.parseInt(location_id);
}
i ++;
}
}
public void drawMiddle()
{
Vector venues = getVenues(category_id);
Hashtable venue_list = (Hashtable) venues.elementAt(0);
Enumeration e = venue_list.keys();
Enumeration v = venue_list.elements();
int count = 0;
while(e.hasMoreElements())
{
String vid = e.nextElement().toString();
Hashtable elm = (Hashtable)v.nextElement();
venueList.addElement(elm);
venue_index.put(Integer.toString(count), (String) elm.get("venue_id"));
EncodedImage img = null;
String image_url = (String) elm.get("image_url");
try
{
String filename;
if(image_url.length() > 5)
{
filename = image_url.substring( image_url.indexOf("crop/") + 5, image_url.length() );
}
else
{
filename = "1.png";
}
FileConnection fconn = (FileConnection) Connector.open( "file:///SDCard/Blackberry/venue/" + filename, Connector.READ);
if ( !fconn.exists() )
{
}
else
{
InputStream input = fconn.openInputStream();
byte[] data = new byte[(int)fconn.fileSize()];
input.read(data);
input.close();
if(data.length > 0)
{
EncodedImage rawimg = EncodedImage.createEncodedImage(data, 0, data.length);
int dw = Fixed32.toFP(Display.getWidth());
int iw = Fixed32.toFP(rawimg.getWidth());
int sf = Fixed32.div(iw, dw);
img = rawimg.scaleImage32(sf * 4, sf * 4);
img_width = (int) Math.ceil(Display.getWidth() / 4);
img_height = (int) Math.ceil(Display.getWidth() / 6);
}
else
{
}
}
}
catch(IOException ef)
{
}
image_index.addElement(img);
count ++;
}
final int count_results = count;
_middle = new VerticalFieldManager( Manager.VERTICAL_SCROLLBAR )
{
public void paint(Graphics graphics)
{
graphics.setBackgroundColor(0xFFFFFF);
graphics.setColor(Color.BLACK);
graphics.clear();
super.paint(graphics);
}
protected void sublayout(int maxWidth, int maxHeight)
{
int displayWidth = Display.getWidth();
//int displayHeight = Display.getHeight();
int displayHeight = count_results * img_height;
super.sublayout( displayWidth, displayHeight);
setExtent( displayWidth, displayHeight);
}
};
add(_middle);
listField = new ListField( venueList.size() );
listField.setCallback( this );
listField.setSelectedIndex(-1);
listField.setRowHeight(img_height);
_middle.add( listField );
_middle.add(new RichTextField(Field.NON_FOCUSABLE));
}
public boolean navigationClick(int status, int time) {
Field focus = UiApplication.getUiApplication().getActiveScreen() .getLeafFieldWithFocus();
if (focus instanceof ListField) {
int selected = listField.getSelectedIndex();
String venue_id = (String) venue_index.get(Integer.toString(selected));
moveScreens(venue_id);
}
return true;
}
void setListSize()
{
listField.setSize( venueList.size() );
}
public void drawListRow( ListField listField, Graphics graphics, int index, int y, int width )
{
Hashtable item = (Hashtable) venueList.elementAt( index );
String venue_name = (String) item.get("name");
String address = (String) item.get("address");
String city = (String) item.get("city");
String zip = (String) item.get("zip");
EncodedImage img = (EncodedImage) image_index.elementAt(index);
graphics.drawText( venue_name, img_width + 10, y, 0, width );
graphics.drawText( address, img_width + 10, y + 15, 0, width );
graphics.drawText( city + ", " + zip, img_width + 10, y + 30, 0, width );
if(img != null)
{
graphics.drawImage(0, y + 3, img.getWidth(), img.getHeight(), img, 0, 0, 0);
}
}
public Object get( ListField listField, int index )
{
return venueList.elementAt( index );
}
public Vector getCategories()
{
Vector results = new Vector();
database db = new database();
Vector categories = db.getCategories();
if(categories.size() > 0)
results = categories;
return results;
}
public Vector getLocations()
{
Vector results = new Vector();
database db = new database();
Vector subcats = db.getCategoryLocations(category_id);
Hashtable subs = (Hashtable) subcats.elementAt(0);
if(subs.size() > 0)
{
location_count = subs.size();
results = subcats;
}
return results;
}
public Vector getVenues(int category_id)
{
Vector results = new Vector();
database db = new database();
Vector venues = db.getLocationVenues(category_id, last_menu_item);
if(venues.size() > 0)
results = venues;
return results;
}
protected void makeMenu(Menu menu, int instance)
{
super.makeMenu(menu, instance);
menu.add(new MenuItem("Home", 10, 20){
public void run()
{
moveScreens("main");
}
});
menu.add(new MenuItem("Search", 10, 20){
public void run()
{
Dialog.inform("Search was clicked.");
}
});
Vector locs = getLocations();
Hashtable locations = (Hashtable) locs.elementAt(0);
Enumeration e = locations.keys();
Enumeration v = locations.elements();
while(e.hasMoreElements())
{
final String location_id = e.nextElement().toString();
String location = v.nextElement().toString();
menu.add(new MenuItem(location, 10, 20){
public void run()
{
Dialog.inform("Location " + location_id + " was clicked");
}
});
}
}
public void moveScreens(String type)
{
if(type == "main")
{
UiApplication.getUiApplication().popScreen(this);
}
else
{
int venue_id = Integer.parseInt(type);
Screen newScreen = new ViewVenue(venue_id);
UiApplication.getUiApplication().pushScreen(newScreen);
}
}
protected void sublayout(int width, int height)
{
super.sublayout(width, height);
if(horizontalOffset > 0)
{
if(animationStart == 0)
{
animationStart = System.currentTimeMillis();
}
else
{
long timeElapsed = System.currentTimeMillis() - animationStart;
if(timeElapsed >= animationTime)
{
horizontalOffset = 0;
}
else
{
float percentDone = (float)timeElapsed / (float)animationTime;
horizontalOffset = Display.getWidth() - (int)(percentDone * Display.getWidth());
}
}
}
setPosition(horizontalOffset, 0);
if(horizontalOffset > 0)
{
UiApplication.getUiApplication().invokeLater(new Runnable(){
public void run()
{
updateLayout();
}
});
}
}
public void fieldChanged(Field field, int context)
{
int id = 0;
if (field instanceof CustomButtonField) {
id = ((CustomButtonField)field).getId();
}
venue_id = id;
Dialog.inform(Integer.toString(venue_id));
//moveScreens("venue");
}
public void focusChanged(Field field, int eventType) {
if((eventType == FocusChangeListener.FOCUS_GAINED)) {
if (field instanceof CustomButtonField) {
final int id = ((CustomButtonField)field).getId();
if(id == last_nav && before_last != last_menu_item && last_nav != before_last)
{
//updateContent(id);
f.setFocus();
}
else
{
updateContent(id);
f = field;
}
}
}
}
public void updateContent(final int id)
{
UiApplication.getUiApplication().invokeLater(new Runnable(){
public void run()
{
delete(_middle);
venueList.removeAllElements();
image_index.removeAllElements();
last_menu_item = id;
drawMiddle();
}
});
}
public boolean onSavePrompt()
{
// do nothing
return true;
}
public int getPreferredWidth(ListField listField) {
// TODO Auto-generated method stub
return 0;
}
public int indexOfList(ListField listField, String prefix, int start) {
// TODO Auto-generated method stub
return 0;
}
}
Do you know some way to programmaticaly show different typing indicators on the screen?
I know I can simply draw bitmap but I'd like to do it universally for any RIM OS version.
Also, there is a setMode(int) function in 4.2.1 but in 4.3 it's already deprecated...
Any suggestions will be helpful, thanks!
since there is no alternatives, I made a sample with provided images:
alt text http://img42.imageshack.us/img42/6692/typeindicator.jpg
alt text http://img3.imageshack.us/img3/5259/inputind.jpg
custom Title Field class code:
class TITitleField extends Field implements DrawStyle {
static final boolean mIsDimTheme = Integer.parseInt(DeviceInfo
.getDeviceName().substring(0, 4)) < 8900;
static final Bitmap ALT = Bitmap.getBitmapResource(mIsDimTheme ?
"typ_ind_alt_mode_Gen_Zen_328560_11.jpg" :
"typ_ind_alt_mode_Precsn_Zen_392908_11.jpg");
static final Bitmap MULTITAP = Bitmap.getBitmapResource(mIsDimTheme ?
"typ_ind_mltap_mode_Gen_Zen_328975_11.jpg" :
"typ_ind_mutlitap_mode_Precsn_Zen_452907_11.jpg");
static final Bitmap NUMLOCK = Bitmap
.getBitmapResource(mIsDimTheme ?
"typ_ind_num_lock_Gen_Zen_328568_11.jpg" :
"typ_ind_num_lock_Precsn_Zen_392925_11.jpg");
static final Bitmap SHIFT = Bitmap.getBitmapResource(mIsDimTheme ?
"typ_ind_shift_mode_Gen_Zen_328574_11.jpg" :
"typ_ind_shift_mode_Precsn_Zen_392931_11.jpg");
public static final int MODE_NONE = 0;
public static final int MODE_ALT = 1;
public static final int MODE_MULTITAP = 2;
public static final int MODE_NUMLOCK = 3;
public static final int MODE_SHIFT = 4;
public void setTypingIndicatorMode(int mode) {
mMode = mode;
updateLayout();
}
public int getTypingIndicatorMode()
{
return mMode;
}
int mWidth = 0;
int mMode = 0;
String mTitle = "";
XYRect mIndicatorDestRect = new XYRect();
public TITitleField() {
this("");
}
public TITitleField(String title) {
mTitle = title;
}
protected void paint(Graphics graphics) {
graphics.drawText(mTitle, 0, 0, LEFT | ELLIPSIS, mWidth);
if (0 != mMode) {
graphics.drawBitmap(mIndicatorDestRect,getIndicator(mMode),0,0);
}
}
private static Bitmap getIndicator(int mode) {
Bitmap result = null;
switch (mode) {
case MODE_ALT:
result = ALT;
break;
case MODE_MULTITAP:
result = MULTITAP;
break;
case MODE_NUMLOCK:
result = NUMLOCK;
break;
case MODE_SHIFT:
result = SHIFT;
break;
case MODE_NONE:
break;
default:
break;
}
return result;
}
protected void layout(int width, int height) {
mWidth = width;
if (0 != mMode) {
Bitmap indicator = getIndicator(mMode);
mIndicatorDestRect.width = indicator.getWidth();
mIndicatorDestRect.height = indicator.getHeight();
mIndicatorDestRect.y = 0;
mIndicatorDestRect.x = mWidth - mIndicatorDestRect.width;
}
setExtent(width, getPreferredHeight());
}
public int getPreferredHeight() {
int height = getFont().getHeight() + 4;
if (0 != mMode) {
int indicatorHeight = getIndicator(mMode).getHeight();
height = Math.max(height, indicatorHeight);
}
return height;
}
}
Sample of use code:
class Scr extends MainScreen {
static final TITitleField mTitle = new TITitleField("Start");
public Scr() {
this.setTitle(mTitle);
}
protected void makeMenu(Menu menu, int instance) {
super.makeMenu(menu, instance);
int typingIndicatorMode = mTitle.getTypingIndicatorMode();
if(typingIndicatorMode != mTitle.MODE_NONE)
menu.add(new MenuItem("None Mode", 0, 0) {
public void run() {
mTitle.setTypingIndicatorMode(mTitle.MODE_NONE);
}
});
if(typingIndicatorMode != mTitle.MODE_ALT)
menu.add(new MenuItem("Alt Mode", 0, 0) {
public void run() {
mTitle.setTypingIndicatorMode(mTitle.MODE_ALT);
}
});
if(typingIndicatorMode != mTitle.MODE_MULTITAP)
menu.add(new MenuItem("Multitap Mode", 0, 0) {
public void run() {
mTitle.setTypingIndicatorMode(mTitle.MODE_MULTITAP);
}
});
if(typingIndicatorMode != mTitle.MODE_NUMLOCK)
menu.add(new MenuItem("NumLock Mode", 0, 0) {
public void run() {
mTitle.setTypingIndicatorMode(mTitle.MODE_NUMLOCK);
}
});
if(typingIndicatorMode != mTitle.MODE_SHIFT)
menu.add(new MenuItem("Shift Mode", 0, 0) {
public void run() {
mTitle.setTypingIndicatorMode(mTitle.MODE_SHIFT);
}
});
}
}
i want to create sub menu for a BB application
when i click on menu item it shows
Option 1
Option 2
Option 3
When i click on option 3 it should display
1
2
3
as sub menu items..
using j2me + eclipse
Always wanted to do this )
alt text http://img380.imageshack.us/img380/3874/menugy.jpg
class Scr extends MainScreen {
SubMenu menu = new SubMenu();
public Scr() {
for (int i = 0; i < 3; i++) {
SubMenu sMenu = new SubMenu();
menu.add(new SubMenuItem(i + " item", sMenu));
for (int k = 0; k < 3; k++) {
SubMenu sSMenu = new SubMenu();
sMenu.add(new SubMenuItem(i + "-" + k + " item", sSMenu));
for (int l = 0; l < 3; l++) {
sSMenu
.add(new SubMenuItem(i + "-" + k + "-" + l
+ " item"));
}
}
}
add(new LabelField("testing menu", FOCUSABLE) {
protected void makeContextMenu(ContextMenu contextMenu) {
menu.mRectangle.x = this.getContentRect().X2();
menu.mRectangle.y = this.getContentRect().Y2();
Ui.getUiEngine().pushScreen(menu);
EventInjector.invokeEvent(new KeyEvent(KeyEvent.KEY_DOWN,
Characters.ESCAPE, 0));
}
});
}
}
class SubMenu extends PopupScreen implements ListFieldCallback {
private static final int MAX_WIDTH = Font.getDefault().getAdvance(
"max menu item text");
XYRect mRectangle = new XYRect();
Vector mSubMenuItems = new Vector();
ListField mListField;
public SubMenu() {
super(new SubMenuItemManager(), DEFAULT_CLOSE);
int rowHeight = getFont().getHeight() + 2;
mListField = new ListField() {
protected boolean navigationClick(int status, int time) {
runMenuItem(getSelectedIndex());
return super.navigationClick(status, time);
}
};
mListField.setRowHeight(rowHeight);
add(mListField);
mListField.setCallback(this);
updateMenuItems();
}
public void add(SubMenuItem subMenuItem) {
mSubMenuItems.addElement(subMenuItem);
subMenuItem.mMenu = this;
updateMenuItems();
}
private void updateMenuItems() {
int rowCounts = mSubMenuItems.size();
mRectangle.width = getMaxObjectToStringWidth(mSubMenuItems);
mRectangle.height = mListField.getRowHeight() * rowCounts;
mListField.setSize(rowCounts);
}
private void runMenuItem(int index) {
SubMenuItem item = (SubMenuItem) get(mListField, index);
if (null != item.mSubMenu) {
item.mSubMenu.setSubMenuPosition(getSubMenuRect(index));
Ui.getUiEngine().pushScreen(item.mSubMenu);
} else {
item.run();
}
}
private XYRect getSubMenuRect(int index) {
SubMenuItem item = (SubMenuItem) get(mListField, index);
XYRect result = item.mSubMenu.mRectangle;
result.x = mRectangle.x + mRectangle.width;
result.y = mRectangle.y + mListField.getRowHeight() * index;
int testWidth = Display.getWidth() - (mRectangle.width + mRectangle.x);
if (testWidth < result.width) {
result.width = testWidth;
}
int testHeight = Display.getHeight()
- (mRectangle.height + mRectangle.y);
if (testHeight < result.height)
result.height = testHeight;
return result;
}
public void setSubMenuPosition(XYRect rect) {
mRectangle = rect;
}
protected void sublayout(int width, int height) {
super.sublayout(mRectangle.width, mRectangle.height);
setPosition(mRectangle.x, mRectangle.y);
setExtent(mRectangle.width, mRectangle.height);
}
private int getMaxObjectToStringWidth(Vector objects) {
int result = 0;
for (int i = 0; i < objects.size(); i++) {
int width = getFont().getAdvance(objects.elementAt(i).toString());
if (width > result) {
if (width > MAX_WIDTH) {
result = MAX_WIDTH;
break;
} else {
result = width;
}
}
}
return result;
}
public void drawListRow(ListField field, Graphics g, int i, int y, int w) {
// Draw the text.
String text = get(field, i).toString();
g.setColor(Color.WHITE);
g.drawText(text, 0, y, DrawStyle.ELLIPSIS, w);
}
public Object get(ListField listField, int index) {
return mSubMenuItems.elementAt(index);
}
public int getPreferredWidth(ListField listField) {
return mRectangle.width;
}
public int indexOfList(ListField listField, String prefix, int start) {
return 0;
}
}
class SubMenuItemManager extends VerticalFieldManager {
public SubMenuItemManager() {
super(USE_ALL_HEIGHT | USE_ALL_WIDTH);
}
public int getPreferredWidth() {
return ((SubMenu) getScreen()).mRectangle.width;
}
public int getPreferredHeight() {
return ((SubMenu) getScreen()).mRectangle.height;
}
protected void sublayout(int maxWidth, int maxHeight) {
maxWidth = getPreferredWidth();
maxHeight = getPreferredHeight();
super.sublayout(maxWidth, maxHeight);
setExtent(maxWidth, maxHeight);
}
}
class SubMenuItem implements Runnable {
String mName;
SubMenu mMenu;
SubMenu mSubMenu;
public SubMenuItem(String name) {
this(name, null);
}
public SubMenuItem(String name, SubMenu subMenu) {
mName = name;
mSubMenu = subMenu;
}
public String toString() {
return mName;
}
public void run() {
}
}
Submenus are not part of the standard BlackBerry API. If you want to do this, you'll have to make your own custom menu+submenu control.